Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用Visual Studio将C“项目的标准输出重定向到文件”;命令行参数";选项_C#_Visual Studio_Visual Studio 2012 - Fatal编程技术网

C# 如何使用Visual Studio将C“项目的标准输出重定向到文件”;命令行参数";选项

C# 如何使用Visual Studio将C“项目的标准输出重定向到文件”;命令行参数";选项,c#,visual-studio,visual-studio-2012,C#,Visual Studio,Visual Studio 2012,我试图将C#程序的输出重定向到一个文件。使用“cmd.exe”时,我可以简单地使用myprogram.exe arg1 arg2>out.txt运行它,但我希望使用Visual Studio启动选项完成同样的任务 我创建了一个C#空项目并添加了以下代码: 使用系统; 课堂测试 { 公共静态void Main(字符串[]args) { foreach(args中的var arg)控制台。WriteLine(arg); } } 然后,我在项目设置中编辑了命令行参数: 使用Ctrl+F5运行项目无

我试图将C#程序的输出重定向到一个文件。使用“cmd.exe”时,我可以简单地使用
myprogram.exe arg1 arg2>out.txt运行它,但我希望使用Visual Studio启动选项完成同样的任务

我创建了一个C#空项目并添加了以下代码:

使用系统;
课堂测试
{
公共静态void Main(字符串[]args)
{
foreach(args中的var arg)控制台。WriteLine(arg);
}
}
然后,我在项目设置中编辑了命令行参数:

使用Ctrl+F5运行项目无法正常工作。我将命令行参数打印在控制台中,而不是输出文件中:

arg1
arg2
>
output.txt
如果我将命令行参数更改为:
arg1 arg2>output.txt“
我将获得以下输出:

arg1
arg2
^> output.txt
我注意到在output文件夹中创建了一个空的
output.txt
文件


这是可以完成的,还是我被迫继续使用cmd.exe来启动我的程序?

我不确定这是否可以在Visual Studio中完成。我的解决方案是为控制台设置一个新的输出。此示例来自MSDN:

Console.WriteLine("Hello World");
FileStream fs = new FileStream("Test.txt", FileMode.Create);
// First, save the standard output.
TextWriter tmp = Console.Out;
StreamWriter sw = new StreamWriter(fs);
Console.SetOut(sw);
Console.WriteLine("Hello file");
Console.SetOut(tmp);
Console.WriteLine("Hello World");
sw.Close();

您可以在外部编辑器中打开
.csproj.user
,并将
StartTargetments
更改为:

<StartArguments>arg1 arg2 &gt; output.txt</StartArguments>
arg1 arg2 output.txt

arg1 arg2>output.txt

在“开始选项”部分,以这种方式更改命令行参数文本框

args1 args2 1>output.txt
这将重定向标准输出(1),创建名为output.txt的文件
如果要附加到文件的早期版本,请写入

args1 args2 1>>output.txt

现在,当输出控制台被重定向时,您可以一步一步地调试程序。严格来说,您必须使用命令提示符以重定向的输出启动程序。否则,您将需要自己解析命令行,GUI shell可能不会这样做

如果您只想在
开始调试时重定向输出
,则取消选中
启用Visual Studio宿主进程
的复选框,即可完成

如果没有,那么您在那里看到的
“output.txt”
实际上不是由应用程序生成的,而是由Visual Studio IDE在开始调试之前生成的
“YourApplication.vshost.exe”
。内容总是空的,不能写;因为它被门锁上了

但是,如果您希望应用程序在任何启动模式下都保持相同的行为,那么事情就更复杂了

当您开始调试应用程序时,它将从以下内容开始:

“YourApplication.exe”arg1 arg2

因为IDE已经重定向了输出

当您在不调试的情况下
启动时,
将从以下内容启动:

%comspec%/c“YourApplication.exe”arg1 arg2^>output.txt暂停(&p)

这是让应用程序获取您指定的所有参数的正确方法

你可能想看看我之前的答案

在这里,我使用的方法如下所示:

  • 应用程序代码

    using System.Diagnostics;
    using System.Linq;
    using System;
    
    class Test {
        public static void Main(string[] args) {
            foreach(var arg in args)
                Console.WriteLine(arg);
        }
    
        static Test() {
            var current=Process.GetCurrentProcess();
            var parent=current.GetParentProcess();
            var grand=parent.GetParentProcess();
    
            if(null==grand
                ||grand.MainModule.FileName!=current.MainModule.FileName)
                using(var child=Process.Start(
                    new ProcessStartInfo {
                        FileName=Environment.GetEnvironmentVariable("comspec"),
                        Arguments="/c\x20"+Environment.CommandLine,
                        RedirectStandardOutput=true,
                        UseShellExecute=false
                    })) {
                    Console.Write(child.StandardOutput.ReadToEnd());
                    child.WaitForExit();
                    Environment.Exit(child.ExitCode);
                }
    #if false // change to true if child process debugging is needed 
            else {
                if(!Debugger.IsAttached)
                    Debugger.Launch();
    
                Main(Environment.GetCommandLineArgs().Skip(1).ToArray());
                current.Kill(); // or Environment.Exit(0); 
            }
    #endif
        }
    }
    
我们还需要以下代码,以便它能够工作:

  • 扩展方法代码

    using System.Management; // add reference is required
    
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    
    using System.Collections.Generic;
    using System.Linq;
    using System;
    
    public static partial class NativeMethods {
        [DllImport("kernel32.dll")]
        public static extern bool TerminateThread(
            IntPtr hThread, uint dwExitCode);
    
        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenThread(
            uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
    }
    
    public static partial class ProcessThreadExtensions /* public methods */ {
        public static void Abort(this ProcessThread t) {
            NativeMethods.TerminateThread(
                NativeMethods.OpenThread(1, false, (uint)t.Id), 1);
        }
    
        public static IEnumerable<Process> GetChildProcesses(this Process p) {
            return p.GetProcesses(1);
        }
    
        public static Process GetParentProcess(this Process p) {
            return p.GetProcesses(-1).SingleOrDefault();
        }
    }
    
    partial class ProcessThreadExtensions /* non-public methods */ {
        static IEnumerable<Process> GetProcesses(
            this Process p, int direction) {
            return
                from format in new[] { 
                    "select {0} from Win32_Process where {1}" }
                let selectName=direction<0?"ParentProcessId":"ProcessId"
                let filterName=direction<0?"ProcessId":"ParentProcessId"
                let filter=String.Format("{0} = {1}", p.Id, filterName)
                let query=String.Format(format, selectName, filter)
                let searcher=new ManagementObjectSearcher("root\\CIMV2", query)
                from ManagementObject x in searcher.Get()
                let process=
                    ProcessThreadExtensions.GetProcessById(x[selectName])
                where null!=process
                select process;
        }
    
        // not a good practice to use generics like this; 
        // but for the convenience .. 
        static Process GetProcessById<T>(T processId) {
            try {
                var id=(int)Convert.ChangeType(processId, typeof(int));
                return Process.GetProcessById(id);
            }
            catch(ArgumentException) {
                return default(Process);
            }
        }
    }
    
    使用系统管理;//添加参考是必需的
    使用System.Runtime.InteropServices;
    使用系统诊断;
    使用System.Collections.Generic;
    使用System.Linq;
    使用制度;
    公共静态局部类NativeMethods{
    [DllImport(“kernel32.dll”)]
    公共静态外部bool TerminateThread(
    IntPtr-hThread,uint-dwExitCode);
    [DllImport(“kernel32.dll”)]
    公共静态外部IntPtr OpenThread(
    uint dwDesiredAccess、bool bInheritHandle、uint dwThreadId);
    }
    公共静态部分类ProcessThreadExtensions/*公共方法*/{
    公共静态无效中止(此进程线程t){
    NativeMethods.TerminateThread(
    OpenThread(1,false,(uint)t.Id),1);
    }
    公共静态IEnumerable GetChildProcess(此进程p){
    返回p.getprocesss(1);
    }
    公共静态进程GetParentProcess(此进程p){
    返回p.GetProcesses(-1).SingleOrDefault();
    }
    }
    部分类ProcessThreadExtensions/*非公共方法*/{
    静态IEnumerable进程(
    这个过程(p,int方向){
    返回
    从新[]{
    “从Win32_进程中选择{0},其中{1}”
    
    让selectName=direction如果要将输出通过管道传输到文件,则必须继续使用cmd.exe。命令行参数:用于命令行参数,因此您尝试的任何内容都将被转义为命令行参数。管道和重定向器不是命令行参数,因此它们将被转义


    我只需要创建一个.bat文件来调用我喜欢的程序。你可以将它固定到任务栏上,然后简单地运行它。

    我建议一种更好的方法,而不需要编写任何代码

    只需将visual studio配置为作为外部程序启动您的程序。

    简单的方法是: 右键单击项目=>属性=>调试


    然后确保在调试模式下运行程序

    ,很遗憾,这在Visual Studio 2012中不起作用。如果从Main()打印args[0],它将在控制台窗口中打印
    1>output.txt
    。我刚刚意识到-只要您至少有一个参数,它就可以工作。如果您只输入
    >output.txt
    它就不工作了…等等{edit}仍然不起作用…嗯,我发现了它是什么-如果按F5在调试器下运行,它会起作用。如果按Ctrl-F5在调试器外运行(但仍从VS启动),则它不起作用。请注意
    using System.Management; // add reference is required
    
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    
    using System.Collections.Generic;
    using System.Linq;
    using System;
    
    public static partial class NativeMethods {
        [DllImport("kernel32.dll")]
        public static extern bool TerminateThread(
            IntPtr hThread, uint dwExitCode);
    
        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenThread(
            uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
    }
    
    public static partial class ProcessThreadExtensions /* public methods */ {
        public static void Abort(this ProcessThread t) {
            NativeMethods.TerminateThread(
                NativeMethods.OpenThread(1, false, (uint)t.Id), 1);
        }
    
        public static IEnumerable<Process> GetChildProcesses(this Process p) {
            return p.GetProcesses(1);
        }
    
        public static Process GetParentProcess(this Process p) {
            return p.GetProcesses(-1).SingleOrDefault();
        }
    }
    
    partial class ProcessThreadExtensions /* non-public methods */ {
        static IEnumerable<Process> GetProcesses(
            this Process p, int direction) {
            return
                from format in new[] { 
                    "select {0} from Win32_Process where {1}" }
                let selectName=direction<0?"ParentProcessId":"ProcessId"
                let filterName=direction<0?"ProcessId":"ParentProcessId"
                let filter=String.Format("{0} = {1}", p.Id, filterName)
                let query=String.Format(format, selectName, filter)
                let searcher=new ManagementObjectSearcher("root\\CIMV2", query)
                from ManagementObject x in searcher.Get()
                let process=
                    ProcessThreadExtensions.GetProcessById(x[selectName])
                where null!=process
                select process;
        }
    
        // not a good practice to use generics like this; 
        // but for the convenience .. 
        static Process GetProcessById<T>(T processId) {
            try {
                var id=(int)Convert.ChangeType(processId, typeof(int));
                return Process.GetProcessById(id);
            }
            catch(ArgumentException) {
                return default(Process);
            }
        }
    }