【问题标题】:MSbuild Copy whole folderMSbuild 复制整个文件夹
【发布时间】:2011-07-04 15:57:28
【问题描述】:

试图复制整个文件夹,但是当我这样做时:

<Copy SourceFiles="$(TargetDir)\*.*" DestinationFolder="$(BuildOutput)\SomeDir" />

复制尝试这样做:复制 c:\source\*.* c:\destination\SomeDir\*.* 并以“非法字符”失败

【问题讨论】:

标签: .net visual-studio msbuild


【解决方案1】:

为 SourceFiles 明确指定您的 ItemGroup。

<ItemGroup>
    <_CopyItems Include="$(TargetDir)\*.*" />
</ItemGroup>
<Copy
    SourceFiles="@(_CopyItems)"
    DestinationFolder="$(BuildOutput)\SomeDir"
    />

请注意,_CopyItems 是一种项目类型,因此使用“@”符号而不是“$”来引用它。

【讨论】:

  • 最好将 &lt;InProject&gt;false&lt;/InProject&gt; 添加到项目组,否则您将在解决方案资源管理器中看到所有 bin 文件夹内容。 &lt;ItemGroup&gt; &lt;_CopyItems Include="$(TargetDir)*.*"&gt; &lt;InProject&gt;false&lt;/InProject&gt; &lt;/_CopyItems&gt; &lt;/ItemGroup&gt;
【解决方案2】:

复制文件可以使用以下代码sn-p来完成,它处理防病毒程序和子目录

  <ItemGroup>
        <SomeAppStuff Include="$(SolutionDir)\ProjectXXX\bins\**\*.*" />
  </ItemGroup>
  <Copy 
      SourceFiles="@(SomeAppStaff)" 
      DestinationFolder="$(OutputPath)\%(RecursiveDir)" 
      SkipUnchangedFiles="true"
      OverwriteReadOnlyFiles="true" 
      Retries="3"
      RetryDelayMilliseconds="300"/>

指定$(OutputPath)\%(RecursiveDir) 将要求复制任务尊重子文件夹,因此它将源目录的子文件夹放置到目标目录的子文件夹中。

SkipUnchangedFiles 将在内存充足的计算机上提高构建速度,因为当内存充足时,Windows 会针对常用文件优化 IO。

RetriesRetryDelayMilliseconds 处理相关问题 a) 压缩的 NTFS 文件系统,在极少数情况下构建失败时 b) 带有 SSD 驱动器的防病毒软件。

【讨论】:

  • DestinationFolder 设置为路径\%(RecursiveDir) 的后果是什么?它会将目录放置在预期的位置,还是递归路径最远的位置,
  • kayleeFrye_onDeck,它将源目录的子文件夹放在目标目录的子文件夹中,如果删除它,源目录的所有子文件夹的内容将被放置到目标目录。
  • 谢谢,我的文件夹正在创建中,但所有文件都放入了根目录,直到我更改为 %(RecursiveDir)
  • 好奇 MS Build 能否处理驱动器号我必须在 msbuild 时创建一个物理文件夹,但它不能在主网站中
【解决方案3】:

如果您将文件夹放在 c# 项目的根目录中,那么您可以简单地将其放在您的 csproj 中。

<ItemGroup>
    <None Update="FolderToCopy\**\*.*">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
</ItemGroup>

我只在 2017 版的 csproj 中进行了测试,但我认为它是向后兼容的。不过可能是错的

【讨论】:

    【解决方案4】:

    查看 MSDN 文档,我相信 SourceFiles 参数需要一个 ITaskItem[] 值。见MSDN MSBuild Copy Task

    上面链接的最后一个例子是从一个目录到另一个目录的递归复制,保持文件夹结构。

    【讨论】:

      【解决方案5】:

      成功完成了这样的任务

      <Target Name="AfterBuild">
        <ItemGroup>
          <SomeDir Include="$(SolutionDir)\SomeOtherProject\SomeDir\**\*" />
        </ItemGroup>
        <Copy 
          SourceFiles="@(SomeDir)" 
          DestinationFiles="@(SomeDir->'$(OutDir)\SomeDir\%(RecursiveDir)%(Filename)%(Extension)')" 
          SkipUnchangedFiles="true" 
          OverwriteReadOnlyFiles="true" 
          Retries="3" 
          RetryDelayMilliseconds="300" />
      

      【讨论】:

        【解决方案6】:

        对我来说有效的是: - 保留文件夹结构 - 复制文件夹中的所有文件 - 适用于任何文件夹,不必在项目或同一个项目文件夹中

        <ItemGroup>
            <_CopyItems Include="<path relative to project>\**\*.*" />
        </ItemGroup>
        
        <Target Name="AfterBuild">
          <Copy SourceFiles="@(_CopyItems)" DestinationFiles="@(_CopyItems->'$(OutDir)\<output folder>\%(RecursiveDir)%(Filename)%(Extension)')"/>
        </Target>
        

        传说:

        • &lt;path relative to project&gt;:这可以是任何路径,使用 ..\ 表示 在 proj 文件夹上方工作
        • &lt;output folder&gt;: 你要的文件夹 要放入的整个文件结构,不包括源 文件夹。
        • $(OutDir) 将是 bin\Debug 或任何你拥有的构建模式,如果你想要什么的话 否则,改变它。

        【讨论】:

          【解决方案7】:

          对我来说最好的解决方案是使用魔法XCOPY,因为我必须复制所有文件和子目录

          <Target Name="PostBuild" AfterTargets="PostBuildEvent">
            <PropertyGroup>
              <FilesSource>$(ProjectDir)\lib</FilesSource>
              <FilesDestination Condition=" '$(SolutionName)' == 'any name a' ">$(ProjectDir)\..\..\Something\lib</FilesDestination>
              <FilesDestination Condition=" '$(SolutionName)' == 'the top solution name' ">$(SolutionDir)\Something\lib</FilesDestination>
            </PropertyGroup>
            <Error Condition=" '$(FilesDestination)' == '' " Text="Lib not delivered. To disable this message, remove the 'Target' tag from the project file" />
            <Exec Command="RD /S /Q &quot;$(FilesDestination)&quot;" />
            <Exec Command="XCOPY &quot;$(FilesSource)&quot; &quot;$(FilesDestination)&quot; /E /I /H /R /K /Y" />
            <Exec Command="RD /S /Q &quot;$(FilesSource)&quot;" />
          </Target>
          

          一旦构建成功,就会触发此构建事件,它会清理FilesDestination 文件夹,然后将所有具有目录结构的文件FilesSource 复制到FilesDestination 和然后它删除FilesSource 文件夹以保留所有“bien propre”:)

          注意

          对于FilesDestination,请确保使用Condition属性或将其删除以结束复制过程

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-03-14
            • 1970-01-01
            • 2014-10-04
            • 2010-09-12
            相关资源
            最近更新 更多