C# Console receive input with pipe
You need to use Console.Read()
and Console.ReadLine()
as if you were reading user input. Pipes replace user input transparently. You can't use both easily (although I'm sure it's quite possible...).
Edit:
A simple cat
style program:
class Program
{
static void Main(string[] args)
{
string s;
while ((s = Console.ReadLine()) != null)
{
Console.WriteLine(s);
}
}
}
And when run, as expected, the output:
C:\...\ConsoleApplication1\bin\Debug>echo "Foo bar baz" | ConsoleApplication1.exe
"Foo bar baz"
C:\...\ConsoleApplication1\bin\Debug>
c# console: how can i read piped input from the command line
If you want to pipe from outputsomething.exe
to dostuffwithinput.exe
it should be
outputsomething.exe|dostuffwithinput.exe some args
Pipe Data From Command Line into C# Console App
Piped outputs from another command are not passed to your application as command line arguments (i.e. args[]
in Main()
). Rather, they need to be read in by your application from the standard input (stdin
). You need to use Console.Read()
or Console.ReadLine()
for that.
C# Console receive input with pipe
You need to use Console.Read()
and Console.ReadLine()
as if you were reading user input. Pipes replace user input transparently. You can't use both easily (although I'm sure it's quite possible...).
Edit:
A simple cat
style program:
class Program
{
static void Main(string[] args)
{
string s;
while ((s = Console.ReadLine()) != null)
{
Console.WriteLine(s);
}
}
}
And when run, as expected, the output:
C:\...\ConsoleApplication1\bin\Debug>echo "Foo bar baz" | ConsoleApplication1.exe
"Foo bar baz"
C:\...\ConsoleApplication1\bin\Debug>
Writing to two standard input pipes from C#
Based on what is written here and on a good night of sleep (where I dreamt that I could use Stream.CopyAsync
), this is the skeleton of the solution:
string pathToFFmpeg = @"C:\ffmpeg\bin\ffmpeg.exe";
string[] inputs = new[] { "video.m4v", "audio.mp3" };
string output = "output2.mp4";
var npsss = new NamedPipeServerStream[inputs.Length];
var fss = new FileStream[inputs.Length];
try
{
for (int i = 0; i < fss.Length; i++)
{
fss[i] = File.OpenRead(inputs[i]);
}
// We use Guid for pipeNames
var pipeNames = Array.ConvertAll(inputs, x => Guid.NewGuid().ToString("N"));
for (int i = 0; i < npsss.Length; i++)
{
npsss[i] = new NamedPipeServerStream(pipeNames[i], PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
}
string pipeNamesFFmpeg = string.Join(" ", pipeNames.Select(x => $@"-i \\.\pipe\{x}"));
using (var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = pathToFFmpeg,
Arguments = $@"-loglevel debug -y {pipeNamesFFmpeg} -c:v copy -c:a copy ""{output}""",
UseShellExecute = false,
}
})
{
Console.WriteLine($"FFMpeg path: {pathToFFmpeg}");
Console.WriteLine($"Arguments: {proc.StartInfo.Arguments}");
proc.EnableRaisingEvents = false;
proc.Start();
var tasks = new Task[npsss.Length];
for (int i = 0; i < npsss.Length; i++)
{
var pipe = npsss[i];
var fs = fss[i];
pipe.WaitForConnection();
tasks[i] = fs.CopyToAsync(pipe)
// .ContinueWith(_ => pipe.FlushAsync()) // Flush does nothing on Pipes
.ContinueWith(x => {
pipe.WaitForPipeDrain();
pipe.Disconnect();
});
}
Task.WaitAll(tasks);
proc.WaitForExit();
}
}
finally
{
foreach (var fs in fss)
{
fs?.Dispose();
}
foreach (var npss in npsss)
{
npss?.Dispose();
}
}
There are various attention points:
Not all formats are compatible with pipes. For example many .mp4 aren't, because they have their moov atom towards the end of the file, but ffmpeg needs it immediately, and pipes aren't searchable (ffmpeg can't go to the end of the pipe, read the moov atom and then go to the beginning of the pipe). See here for example
I receive an error at the end of the streaming. The file seems to be correct. I don't know why. Some other persons signaled it but I haven't seen any explanation
\.\pipe\55afc0c8e95f4a4c9cec5ae492bc518a: Invalid argument
\.\pipe\92205c79c26a410aa46b9b35eb3bbff6: Invalid argumentI don't normally use
Task
andAsync
, so I'm not 100% sure if what I wrote is correct. This code doesn't work for example:tasks[i] = pipe.WaitForConnectionAsync().ContinueWith(x => fs.CopyToAsync(pipe, 4096)).ContinueWith(...);
Mmmmh perhaps the last can be solved:
tasks[i] = ConnectAndCopyToPipe(fs, pipe);
and then
public static async Task ConnectAndCopyToPipe(FileStream fs, NamedPipeServerStream pipe)
{
await pipe.WaitForConnectionAsync();
await fs.CopyToAsync(pipe);
// await fs.FlushAsync(); // Does nothing
pipe.WaitForPipeDrain();
pipe.Disconnect();
}
Pass text file content to Console.ReadLine() instead of typing
Thanks @Marc Gravell and @Olivier Rogier.
Answer is to use pipes.
myconsoleapp main.cs
Public static void main(args){
String input = Console.ReadLine();
Console.WriteLine(input);
}
input.txt file
Hello world
Command-line
myconsoleapp.exe < input.txt
output
Hello world
Reference:
ss64.com/nt/syntax-redirection.html
How-to: Redirection
command > filename Redirect command output to a file
command >> filename APPEND into a file
command < filename Type a text file and pass the text to command
commandA | commandB Pipe the output from commandA into commandB
commandA & commandB Run commandA and then run commandB
commandA && commandB Run commandA, if it succeeds then run commandB
commandA || commandB Run commandA, if it fails then run commandB
commandA && commandB || commandC
If commandA succeeds run commandB, if commandA fails run commandC
( Note that if commandB fails, that will also trigger running commandC )
Related Topics
Compare Version Numbers Without Using Split Function
Why Does Enumerable.All Return True for an Empty Sequence
How Is Performance Affected by an Unused Using Directive
Will the Dynamic Keyword in C#4 Support Extension Methods
How to Restrict/Control the Navigation Routes the User Can Visit Based on Login Status/Role
Why Can't C# Interfaces Contain Fields
How to Flatten Nested Objects with Linq Expression
Why Do We Need the New Keyword and Why Is the Default Behavior to Hide and Not Override
Get Property Name and Type Using Lambda Expression
Populate Data Table from Data Reader
Find Index of a Value in an Array
How to Select Min and Max Values of a Column in a Datatable
Why Is Ushort + Ushort Equal to Int
Listbox Items Return String, When Datatemplate Is Button
What Does the Word "Literal" Mean
Why Isn't Array a Generic Type
How to Determine for Which Platform an Executable Is Compiled