草庐IT

c# - 如何使用 Visual Studio "command line arguments"选项将 C# 项目的标准输出重定向到文件

coder 2023-07-13 原文

我正在尝试将 C# 程序的输出重定向到一个文件。使用“cmd.exe”时,我可以简单地使用 myprogram.exe arg1 arg2 > out.txt 运行它,但我想使用 Visual Studio Start Options.

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

using System;
class Test
{
    public static void Main(string[] args)
    {
        foreach (var arg in args) Console.WriteLine(arg);
    }
}

然后我在项目设置中编辑了命令行参数:

使用 Ctrl+F5 运行项目无法按预期运行。我在控制台而不是输出文件中打印了命令行参数:

arg1
arg2
>
output.txt

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

arg1
arg2
^> output.txt

我注意到在 Output 文件夹中创建了一个空的 output.txt 文件。

这件事有可能完成还是我被迫继续使用 cmd.exe 来启动我的程序?

最佳答案

从严格意义上讲,您被迫使用命令提示符启动带有重定向输出的程序。否则,您需要自己解析命令行,GUI shell 可能不会这样做。

如果您只是想在 Start Debugging 时重定向输出,然后取消选中 Enable the Visual Studio hosting process 复选框,您就完成了。

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

但是,如果您希望应用程序无论以何种模式启动都表现得一样,事情就更复杂了。

当您开始调试应用程序时,它开始于:

"YourApplication.exe" arg1 arg2

因为输出已经被 IDE 重定向了。

当你Start Without Debugging时,它开始于:

"%comspec%" /c ""YourApplication.exe" arg1 arg2 ^>output.txt & pause"

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

您可能想看看我之前对 How can I detect if "Press any key to continue . . ." will be displayed? 的回答.

这里我使用了类似 atavistic throwback 的方法在下面的代码中:

  • 申请代码

    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);
            }
        }
    }
    

因为在我们调试时,父级将是 Visual Studio IDE(当前名为 "devenv")。父进程和祖父进程实际上是多种多样的,我们需要一个规则来执行一些检查。

棘手的部分 是真正遇到Main 的是孙子。代码在每次运行时检查祖父进程。如果祖 parent 是 null 那么它会产生,但产生的进程将是 %comspec%,这也是它将以相同的可执行文件启动的新进程的父进程当前。因此,如果祖 parent 与自己相同,那么它就不会继续生成,只会遇到 Main

Static Constructor在代码中使用,在Main之前启动。 SO 上有一个已回答的问题:How does a static constructor work? .

当我们开始调试时,我们正在调试祖父进程(产生)。为了使用孙子进程进行调试,我制作了带有条件编译的 Debugger.Launch,它将调用 Main,以保持 Main 清晰。

有关调试器的已回答问题也会有所帮助:Attach debugger in C# to another process .

关于c# - 如何使用 Visual Studio "command line arguments"选项将 C# 项目的标准输出重定向到文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16262394/

有关c# - 如何使用 Visual Studio "command line arguments"选项将 C# 项目的标准输出重定向到文件的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  4. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  5. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  6. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  7. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  8. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  9. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  10. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

随机推荐