使用msbuild复制所有文件和文件夹


93

我只是想知道是否有人可以通过我尝试编写的某些msbuild脚本来帮助我。我想做的是使用msbuild将所有文件和子文件夹从一个文件夹复制到另一个文件夹。

{ProjectName}
      |----->Source
      |----->Tools
              |----->Viewer
                       |-----{about 5 sub dirs}

我需要做的是将所有文件和子文件夹从tools文件夹复制到应用程序的debug文件夹中。这是我到目前为止的代码。

 <ItemGroup>
<Viewer Include="..\$(ApplicationDirectory)\Tools\viewer\**\*.*" />
 </ItemGroup>

<Target Name="BeforeBuild">
        <Copy SourceFiles="@(Viewer)" DestinationFolder="@(Viewer->'$(OutputPath)\\Tools')" />
  </Target>

生成脚本会运行,但是不会复制任何文件或文件夹。

谢谢

Answers:


132

我也在寻找帮助。我花了一段时间,但这是我所做的,效果很好。

<Target Name="AfterBuild">
    <ItemGroup>
        <ANTLR Include="..\Data\antlrcs\**\*.*" />
    </ItemGroup>
    <Copy SourceFiles="@(ANTLR)" DestinationFolder="$(TargetDir)\%(RecursiveDir)" SkipUnchangedFiles="true" />
</Target>

这个递归复制命名的文件夹中的内容antlrcs$(TargetDir)


4
是的,这是最好的答案。与此处在msdn博客上的建议相同:blogs.msdn.com/b/msbuild/archive/2005/11/07/490068.aspx
Karsten

2
效果很好-谢谢!我不知道为什么其他更复杂的答案会有更多的赞誉?
伊万

17
窍门似乎是添加%(RecursiveDir)到目标文件夹将重新创建目录结构。否则输出是平坦的。这是最佳答案。
JB。和莫妮卡

1
需要放在.fsproj文件的底部,否则不需要。
亨里克

对我有用的关键时刻是在AfterBuild目标下移动变量声明(<ANTLR Include =“ .. \ Data \ antlrcs ***。*” />)。就我而言,它是在外部范围中声明的,并且不起作用。
Shpand

71

我认为问题可能出在您如何创建ItemGroup和调用Copy任务上。看看这是否有意义:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
    <PropertyGroup>
        <YourDestinationDirectory>..\SomeDestinationDirectory</YourDestinationDirectory>
        <YourSourceDirectory>..\SomeSourceDirectory</YourSourceDirectory>
    </PropertyGroup>

    <Target Name="BeforeBuild">
        <CreateItem Include="$(YourSourceDirectory)\**\*.*">
            <Output TaskParameter="Include" ItemName="YourFilesToCopy" />
        </CreateItem>

        <Copy SourceFiles="@(YourFilesToCopy)"
                DestinationFiles="@(YourFilesToCopy->'$(YourDestinationDirectory)\%(RecursiveDir)%(Filename)%(Extension)')" />
    </Target>
</Project>

CreateItem任务已弃用。正则表达式可以替代。msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Ray Cheng

35

我是MSBuild的新手,但是我发现EXEC Task非常适合此类情况。我在项目中遇到了同样的挑战,这对我有用,而且简单得多。有人请告诉我这是否不是一个好习惯。

<Target Name="CopyToDeployFolder" DependsOnTargets="CompileWebSite">
    <Exec Command="xcopy.exe  $(OutputDirectory) $(DeploymentDirectory) /e" WorkingDirectory="C:\Windows\" />
</Target>

9
相反,我敢问这个问题。是否有任何理由使用日志填充msbuild复制任务?
bernd_k 2012年

4
潜在地。如果您有一个构建场(Jenkins,TeamCity等),则代理服务可能会在路径中没有xcopy的其他帐户下运行。您可以在路径中尝试诸如%windir%\ system32之类的操作,但有时甚至无法正常工作。
安德鲁dh13年

那是对我有用的解决方案。另外,我不需要设置WorkingDirectory。
Aebsubis

仅供参考,我需要添加/ Y以禁止显示文件/文件夹覆盖提示。同样,如果$(DeploymentDirectory)是文件夹,则在路径后留下“ \”将删除提示:“目标是文件夹还是文件?”
霍隆2015年

6
我知道这个问题不会经常出现,但是我使用Copy任务而不是命令的主要原因是兼容性。我以前在Linux上使用Mono进行构建,但显然xcopy在那里不起作用。
GregRos

12
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
    <PropertyGroup>
        <YourDestinationDirectory>..\SomeDestinationDirectory</YourDestinationDirectory>
        <YourSourceDirectory>..\SomeSourceDirectory</YourSourceDirectory>
    </PropertyGroup>

    <Target Name="BeforeBuild">
        <CreateItem Include="$(YourSourceDirectory)\**\*.*">
            <Output TaskParameter="Include" ItemName="YourFilesToCopy" />
        </CreateItem>

        <Copy SourceFiles="@(YourFilesToCopy)"
                DestinationFiles="$(YourFilesToCopy)\%(RecursiveDir)" />
    </Target>
</Project>

\**\*.*帮助从所有文件夹中获取文件。RecursiveDir帮助将所有文件放在相应的文件夹中...


2
目标文件涉及1个项目,源文件涉及33个项目。它们必须具有相同数量的项目。嗯,.msbuild可能很棒,但有时记录得这么烂,只是垃圾。
松饼人2014年

CreateItem任务已弃用。正则表达式可以替代。msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Ray Cheng

4

您是否尝试指定具体的目标目录而不是

DestinationFolder="@(Viewer->'$(OutputPath)\\Tools')" ? 

我对高级MSBuild语法不是很熟练,但是

@(Viewer->'$(OutputPath)\\Tools') 

对我来说看起来很奇怪。脚本看起来不错,所以问题可能出在$(ApplicationDirectory)和的$(OutputPath)

编辑:

这是一篇可能有用的博客文章:

如何:使用任务递归复制文件


1
+1为链接,这比zXen接受的答案更简洁。
bernd_k 2012年

3

这是有效的示例:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <ItemGroup>
      <MySourceFiles Include="c:\MySourceTree\**\*.*"/>
   </ItemGroup>

   <Target Name="CopyFiles">
      <Copy
        SourceFiles="@(MySourceFiles)"
        DestinationFiles="@(MySourceFiles->'c:\MyDestinationTree\%(RecursiveDir)%(Filename)%(Extension)')"
       />
    </Target>

</Project>

来源:https : //msdn.microsoft.com/en-us/library/3e54c37h.aspx


2

这是我在自己的项目中使用的复制任务,对我而言,将带有子文件夹的文件夹成功复制到目标位置的工作非常完美:

<ItemGroup >
<MyProjectSource Include="$(OutputRoot)/MySource/**/*.*" />
</ItemGroup>

<Target Name="AfterCopy" AfterTargets="WebPublish">
<Copy SourceFiles="@(MyProjectSource)" 
 OverwriteReadOnlyFiles="true" DestinationFolder="$(PublishFolder)api/% (RecursiveDir)"/>

就我而言,我将项目的发布文件夹复制到另一个目标文件夹,我认为它与您的案例相似。



0

使用MSBuild将文件从一个目录递归复制到另一个目录的最佳方法是将Copy任务与SourceFiles和DestinationFiles作为参数一起使用。例如-将所有文件从构建目录复制到备份目录将是

<PropertyGroup>
<BuildDirectory Condition="'$(BuildDirectory)' == ''">Build</BuildDirectory>
<BackupDirectory Condition="'$(BackupDiretory)' == ''">Backup</BackupDirectory>
</PropertyGroup>

<ItemGroup>
<AllFiles Include="$(MSBuildProjectDirectory)/$(BuildDirectory)/**/*.*" />
</ItemGroup>

<Target Name="Backup">
<Exec Command="if not exist $(BackupDirectory) md $(BackupDirectory)" />
<Copy SourceFiles="@(AllFiles)" DestinationFiles="@(AllFiles-> 
'$(MSBuildProjectDirectory)/$(BackupDirectory)/%(RecursiveDir)/%(Filename)% 
(Extension)')" />
</Target>

现在,在上面的“复制”命令中,将遍历所有源目录,并将文件复制到目标目录。


0

如果您正在使用典型的C ++工具链,则另一种方法是将文件添加到标准CopyFileToFolders列表中

<ItemGroup>
  <CopyFileToFolders Include="materials\**\*">
    <DestinationFolders>$(MainOutputDirectory)\Resources\materials\%(RecursiveDir)</DestinationFolders>
  </CopyFileToFolders>
</ItemGroup>

除了简单之外,这也是一种不错的方法,因为CopyFilesToFolders任务将生成适当的输入,输出甚至TLog文件,因此确保仅当输入文件之一已更改或输出文件之一丢失时才执行复制操作。使用TLog,Visual Studio还将正确识别项目是否为“最新”(为此它使用了单独的U2DCheck机制)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.