我试图复制一个整个文件夹,但是当我这样做时:
<Copy SourceFiles="$(TargetDir)\*.*" DestinationFolder="$(BuildOutput)\SomeDir" />
该复制命令试图执行以下操作:将 c:\source\. 复制到 c:\destination\SomeDir\.,但是会因为出现了非法字符
而失败。
我试图复制一个整个文件夹,但是当我这样做时:
<Copy SourceFiles="$(TargetDir)\*.*" DestinationFolder="$(BuildOutput)\SomeDir" />
该复制命令试图执行以下操作:将 c:\source\. 复制到 c:\destination\SomeDir\.,但是会因为出现了非法字符
而失败。
明确指定您的SourceFiles的ItemGroup。
<ItemGroup>
<_CopyItems Include="$(TargetDir)\*.*" />
</ItemGroup>
<Copy
SourceFiles="@(_CopyItems)"
DestinationFolder="$(BuildOutput)\SomeDir"
/>
请注意,_CopyItems是一种项目类型,因此使用“@”符号而不是“$”进行引用。<InProject>false</InProject>
,否则您将在解决方案资源管理器中看到所有的 bin 文件夹内容。
<ItemGroup> <_CopyItems Include="$(TargetDir)*.*"> <InProject>false</InProject> </_CopyItems> </ItemGroup>
- Zelenov可以使用以下代码片段复制文件,该代码片段处理防病毒程序和子目录
<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。
Retries
和RetryDelayMilliseconds
处理以下问题:
a)压缩的NTFS文件系统,在极少数情况下构建失败;
b)使用SSD驱动器的杀毒软件。
DestinationFolder
设置为 path%(RecursiveDir) 的后果是什么?它会将目录放置在预期位置,还是放置在递归路径中最深的位置? - kayleeFrye_onDeck%(RecursiveDir)
。 - Aaron如果你将文件夹放在C#项目的根目录下,那么你可以简单地将此内容放入你的csproj文件中。
<ItemGroup>
<None Update="FolderToCopy\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
我只在2017版本的csproj中进行了测试,但我认为它是向后兼容的。不过可能我错了。
根据MSDN文档,我认为SourceFiles参数需要一个ITaskItem[]值。请参见MSDN MSBuild Copy Task
上述链接中的最后一个示例是将一个目录递归复制到另一个目录,同时保留文件夹结构。
<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" />
<ItemGroup>
<_CopyItems Include="<path relative to project>\**\*.*" />
</ItemGroup>
<Target Name="AfterBuild">
<Copy SourceFiles="@(_CopyItems)" DestinationFiles="@(_CopyItems->'$(OutDir)\<output folder>\%(RecursiveDir)%(Filename)%(Extension)')"/>
</Target>
说明:
<相对于项目的路径>
:这可以是任何路径,使用 ..\ 跳出 proj 文件夹即可。<输出文件夹>
:你想要整个文件结构被放置的文件夹,不包括源文件夹。$(OutDir)
将会是 bin\Debug 或者任何其他的编译模式,如果你想要其他的,请更改它。在 Visual Studio 15.4+ 中,有一个功能使这更容易 - 您可以设置LinkBase
或Link
来控制目标路径:
<ItemGroup>
<Content Include="FolderToCopy\**" LinkBase="FolderInOutput\" CopyToOutputDirectory="Always" />
</ItemGroup>
来源:https://github.com/dotnet/msbuild/issues/2949#issuecomment-362823310
这是一个已知问题,MSBuild在处理多个项目引用时可能会出现这种情况。
我们已经为此创建了一个修复程序,该程序将在下一个.NET Core更新中发布。
在等待此修复程序发布之前,您可以通过在单独的msbuild.exe进程中构建解决方案来避免此问题。
对我来说最好的解决方案是使用神奇的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 "$(FilesDestination)"" />
<Exec Command="XCOPY "$(FilesSource)" "$(FilesDestination)" /E /I /H /R /K /Y" />
<Exec Command="RD /S /Q "$(FilesSource)"" />
</Target>
这个构建事件在构建成功后触发,清理FilesDestination
文件夹,然后将FilesSource
中的带有目录结构的全部文件复制到FilesDestination
中,最后删除FilesSource
文件夹以使一切保持“bien propre” :)
注意
对于FilesDestination
,请确保使用Condition属性或将其删除,以便将复制过程执行到底。