【问题标题】:Copy to Output Directory copies folder structure but only want to copy files复制到输出目录复制文件夹结构但只想复制文件
【发布时间】:2010-11-04 02:14:24
【问题描述】:

我有一个 VS2008,我想将某个目录中的某些文件复制到我的 /bin/ 文件夹中。我已将文件(位于/common/browserhawk/)设置为“复制到输出目录”。但是,它也会复制文件夹结构:文件被复制到/bin/common/browserhawk/

如何将这些文件复制到 /bin/?我不想将这些存储在网站的根目录中以使它们正确复制。

相关问题:Visual Studio adds .dll and .pdb to project after compiling

【问题讨论】:

    标签: visual-studio-2008 msbuild


    【解决方案1】:

    我在 VS2010、VS2015、VS2017 和 VS2019 中使用过这个。我更喜欢这个解决方案,因为:

    1. XML 可在任何项目中重复使用
    2. “RootContent”被选为 Visual Studio UI 中的构建操作,就像任何其他“内容”一样
    3. 正如您所期望的那样,“CopyToOutputDirectory”得到了遵守
    4. RootContent 被添加到项目的输出中:通过 Project-References 进行,遵循“干净”等。
    5. 可以使用通配符指定 RootContent,保留递归文件夹结构:
    <RootContent Include="common\browserhawk\**">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </RootContent>
    

    接近项目文件的开头:

      <ItemGroup>
        <AvailableItemName Include="RootContent">
          <!-- Add "RootContent" as a choice in the "Build Action" dropdown. -->
          <Visible>True</Visible>
        </AvailableItemName>
      </ItemGroup>
    

    Borrowed From This Answer

    Microsoft .targets 导入后:

      <PropertyGroup>
        <AssignTargetPathsDependsOn>
          $(AssignTargetPathsDependsOn);
          IncludeRootContentAsContent;
        </AssignTargetPathsDependsOn>
      </PropertyGroup>
      <Target Name="IncludeRootContentAsContent">
        <CreateItem Include="@(RootContent)" AdditionalMetadata="TargetPath=%(RecursiveDir)%(Filename)%(Extension)">
          <Output ItemName="ContentWithTargetPath" TaskParameter="Include" />
        </CreateItem>
      </Target>
    

    Borrowed From This Answer

    【讨论】:

    • 这很好 - 我会换掉 RootContent 这意味着“硬编码”到 CustomContent 以表明这是我们添加到这个项目的特殊内容,我们需要以这种特殊方式复制.另外顺便说一句,我需要TargetPath=%(RecursiveDir)%(Filename)%(Extension) 重新创建从指定的CustomContent 文件到输出路径的文件夹结构。
    • @Jonno 目标是将文件直接复制到根输出目录,而不考虑 RecursiveDirectory。内置的“内容”构建操作已经为我们提供了一种在维护 RecursiveDirectory 的同时进行复制的机制。
    • 我有一段时间没有机会对此进行测试,但不会像 OP 所说的那样设置“内容”构建操作导致 /common/browserhawk/ 下的文件复制到 /bin/common/browserhawk/ 吗? IIRC,我的意图是让/common/browserhawk/a.txt/bin/a.txt 结尾,但允许从那里向下递归,所以/common/browserhawk/secret/stuff.png/bin/secret/stuff.png 结尾。
    • @Jonno 好的,是的,现在完全有道理。我更新了答案以包含%(RecursiveDirectory)。这真的很酷,因为除了在 IDE 中选择单个文件之外,您还可以使用通配符指定多个文件。使用** 通配符时,将保留整个文件夹结构。
    • 非常感谢您提供这么好的答案!我认为这个答案是正确的答案,原因如下:1.没有外部cmds 2.跨平台
    【解决方案2】:

    您可以添加构建后事件来复制文件。
    转到项目属性,构建事件选项卡并将以下内容添加到构建后事件命令行:

    copy "$(ProjectDir)\common\browserhawk\*.*" "$(TargetDir)"
    

    如果您的项目路径中有空格,请务必包含引号。

    【讨论】:

    • 感谢您的建议,因为它在 VS2012 中也对我有用。
    • 在我的情况下我稍微修改了一下:xcopy /s /d /y "$(ProjectDir)\stuff" "$(TargetDir)\stuff"
    【解决方案3】:

    如果您在文本编辑器中编辑 .csproj / .vbproj,您可以控制文件在输出目录中的放置位置,以及文件在输出目录中的名称。例如:

    <None Include="content\someContent.txt">
      <Link>someContentInOutputDirectory.txt</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    

    这会将文件content\someContent.txt 放入bin\someContentInOutputDirectory.txt。如果需要,您也可以选择bin 中的子目录;只需将其添加到 Link 元素即可。

    【讨论】:

    • 哇,我很幸运现在需要这个,而不是两天前。谢谢;这太棒了!
    • 天哪,谢谢。我只花了 6 个小时试图修复一些 VS 没有以智能方式复制 .dll 的极端情况垃圾。这是生命、宇宙和一切的真正答案。
    • 这是迄今为止最好的解决方案
    • 我发现一旦我完成此操作并在 Visual Studio 中重新加载项目,依赖文件就会从解决方案资源管理器中消失,就好像没有包含在项目中一样。然而,它仍然按预期构建,并根据需要复制到输出。作为一种解决方法,我目前将每个文件添加两次;一次没有任何操作,一次设置了“复制到输出”。
    • 这不是该标签的预期用途。在 VS2013 中,这会在加载项目时引发警告,并且该文件在添加到项目时不可见,因为它是项目目录。
    【解决方案4】:

    由于无法评论之前的答案,我将解决方案放在这里:

    除了@PaulAlexander 提供的内容之外,将以下内容添加到您的 .csproj/.vbproj 文件中:

    <ItemGroup>
        <AvailableItemName Include="RootContent">
          <Visible>false</Visible>
        </AvailableItemName>  
    </ItemGroup>
    <Target Name="AfterBuild">
        <Copy
            DestinationFolder="$(OutputPath)"
            SourceFiles="@(RootContent)"
            SkipUnchangedFiles="true"
            />  
    </Target>
    

    这允许您在“属性”窗口中选择“RootContent”作为构建操作,并且可以通过 GUI 访问所有内容。 更完整的解释:“AvailableItemName”选项基本上创建了一个新的命名列表,您可以将项目中的项目分配到“属性”窗口的“构建操作”属性下。然后,您可以在您喜欢的任何目标中使用这个新创建的列表(例如,通过“@(RootContent)”)。

    【讨论】:

    • 不错的答案,我自己就用这个成功了!
    • 另请注意,如果您在 VS 中编辑项目文件,VS 2010(不确定旧版本)会抱怨 AvailableItemName 是无效元素;忽略警告,它仍然有效。
    • 不幸的是,这只会将文件复制到文件所属项目的输出目录中 - 而不是在启动项目的输出目录中。在库项目中使用它时这一点很重要。
    • 这非常适合使用 vs2008 在发布和调试模式下构建,但在使用一键发布时似乎不起作用。有什么建议吗?
    • 在 vs2015 中不适合我。通过稍微重写目标来修复:&lt;Target Name="RootOutputCopyTarget" AfterTargets="Build"&gt; ...
    【解决方案5】:

    我相信 XCOPY 命令可以更好地处理目录和文件。因此,

        XCOPY "$(ProjectDir)common/browserhawk" "$(TargetDir)" /E /I /F /Y
    

    这允许在目标目录之外创建文件夹。

        XCOPY "$(ProjectDir)Templates" "$(TargetDir)" /E /I /F /Y
    

    项目文件夹/文件结构:

        A:\TEMP\CONSOLEAPPLICATION3\TEMPLATES
        ├───NewFolder1
        ├───NewFolder2
        │       TextFile1.txt
        │       TextFile2.txt
        └───NewFolder3
                TextFile1.txt
                TextFile2.txt
                TextFile3.txt
    

    变成:

        A:\TEMP\CONSOLEAPPLICATION3\BIN\DEBUG
        │   ConsoleApplication3.exe
        │   ConsoleApplication3.pdb
        │   ConsoleApplication3.vshost.exe
        │   ConsoleApplication3.vshost.exe.manifest
        ├───NewFolder1
        ├───NewFolder2
        │       TextFile1.txt
        │       TextFile2.txt
        │
        └───NewFolder3
                TextFile1.txt
                TextFile2.txt
                TextFile3.txt
    

    【讨论】:

    • /D 也可能很有用,以避免覆盖可能的更改。
    【解决方案6】:

    将以下内容添加到您的 .csproj/.vbproj 文件中

    <Target Name="AfterBuild">
        <Copy
            DestinationFolder="$(OutputPath)"
            SourceFiles="@(RootContent)"
            SkipUnchangedFiles="true"
            />  
    </Target>
    

    然后将根文件夹中您想要的任何文件的 Build Action 更改为 RootContent。

    【讨论】:

    • 不是通过对话框...但是您可以在 VS 中编辑您的项目。右键单击项目并选择卸载项目。然后右键单击并选择编辑。然后您可以编辑作为您的项目的 MSBuild 文件。
    • 谢谢,这看起来很有用。不幸的是,即使将 sn-p 添加到 .vbproj 文件后,RootContent 也不会显示在“构建操作”下拉列表中,手动输入会导致 Visual Studio 出现“属性值无效”错误。我错过了什么?
    • 不适用于 Visual Studio 2010 C# 控制台应用程序项目。
    • 不适用于 Visual Studio 2010 VB.NET 控制台应用程序项目。
    • 不适用于 Visual Studio 2008 C# 控制台应用程序项目。
    【解决方案7】:

    我最终在成功编译后向 nant 构建文件添加了一个步骤以进行复制

    <target name="action.copy.browserhawk.config" depends="compile.source">
        <copy todir="${App.Web.dir}/bin/" includeemptydirs="false">
            <fileset basedir="${browserhawk.config.dir}">
                <include name="bhawk_bb.dat" />
                <include name="bhawk_sp.dat" />
                <include name="browserhawk.properties" />
                <include name="maindefs.bdd" />
                <include name="maindefs.bdf" />
                <include name="BH_PRO.lic" />
            </fileset>
        </copy>
        <echo message="COPY BROWSERHAWK CONFIG: SUCCESS   ${datetime::now()}" />
    </target>
    

    【讨论】:

    • +1 因为对于使用 nant 的人来说,这仍然是一个有用的答案
    【解决方案8】:

    您可以构建一个批处理文件来复制文件并将其作为构建后事件执行。

    【讨论】:

    • 我最终为我的一个项目这样做(尽管我使用的是 Python 脚本而不是 bat)。
    猜你喜欢
    • 2021-05-24
    • 2020-04-06
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 2012-02-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多