Copy to Output Directory sao chép cấu trúc thư mục nhưng chỉ muốn sao chép tệp


87

Tôi có một VS2008 Tôi muốn sao chép các tệp nhất định từ một thư /bin/mục vào thư mục của mình . Tôi đã đặt các tệp (nằm trong /common/browserhawk/) thành "Sao chép vào Thư mục đầu ra". Tuy nhiên, nó cũng sao chép cấu trúc thư mục: các tệp được sao chép vào/bin/common/browserhawk/

Làm cách nào để tôi chỉ sao chép các tệp này vào /bin/? Tôi không muốn lưu trữ chúng trong thư mục gốc của trang web để chúng sao chép chính xác.

Câu hỏi liên quan: Visual Studio thêm .dll và .pdb vào dự án sau khi biên dịch

Câu trả lời:


59

Bạn có thể thêm Sự kiện tạo bài đăng để sao chép tệp.
Đi tới thuộc tính dự án, tab Xây dựng sự kiện và thêm phần sau vào dòng lệnh Hậu tạo sự kiện:

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

Đảm bảo bao gồm các dấu ngoặc kép nếu đường dẫn dự án của bạn có khoảng trống trong đó.


Cảm ơn vì lời khuyên đó, vì nó cũng vừa hiệu quả với tôi trong VS2012.
Dib

2
Tôi đã sửa đổi này nhẹ trong trường hợp của tôi:xcopy /s /d /y "$(ProjectDir)\stuff" "$(TargetDir)\stuff"
Danny Staple

44

Vì tôi không thể bình luận về các câu trả lời trước đó, tôi sẽ đặt giải pháp ở đây:

Thêm vào những gì @PaulAlexander đã cung cấp, hãy thêm phần sau vào tệp .csproj / .vbproj của bạn:

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

Điều này cho phép bạn chọn "RootContent" làm Hành động xây dựng trong cửa sổ Thuộc tính và tất cả đều có thể được truy cập thông qua GUI. Giải thích đầy đủ hơn: tùy chọn "AvailableItemName" về cơ bản tạo danh sách có tên mới mà bạn có thể gán các mục trong dự án trong thuộc tính "Build Action" trong cửa sổ Properties. Sau đó, bạn có thể sử dụng danh sách mới được tạo này trong bất kỳ Mục tiêu nào bạn thích (ví dụ: thông qua "@ (RootContent)").


Câu trả lời hay, chỉ cần bản thân tôi sử dụng điều này để thành công!
Chris Marisic

Cũng lưu ý rằng VS 2010 (không chắc chắn về các phiên bản cũ hơn) sẽ phàn nàn về việc AvailableItemNamelà một phần tử không hợp lệ nếu bạn chỉnh sửa tệp dự án trong VS; chỉ cần bỏ qua cảnh báo, nó vẫn hoạt động.
Aaronaught

2
Thật không may, điều này chỉ sao chép tệp vào thư mục đầu ra của dự án mà tệp đó thuộc về - chứ không phải trong thư mục đầu ra của dự án khởi động. Điều này rất quan trọng khi sử dụng nó trong một dự án thư viện.
Sebastian Krysmanski

2
Điều này hoạt động tuyệt vời để xây dựng trong chế độ phát hành và gỡ lỗi với vs2008 nhưng nó dường như không hoạt động khi sử dụng xuất bản bằng một cú nhấp chuột. Bất kỳ đề xuất?
Soenhay

2
Không làm việc cho tôi trong vs2015. Đã sửa bằng cách viết lại target một chút: <Target Name="RootOutputCopyTarget" AfterTargets="Build">... </Target>
lorond

44

Nếu bạn chỉnh sửa .csproj / .vbproj trong trình soạn thảo văn bản, bạn có thể kiểm soát vị trí tệp được đặt trong thư mục đầu ra và cả tên tệp sẽ có trong thư mục đầu ra. Ví dụ:

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

Điều này sẽ đưa tệp content\someContent.txtvào bin\someContentInOutputDirectory.txt. Bạn cũng có thể chọn một thư mục con binnếu bạn muốn; chỉ cần thêm nó vào phần tử Liên kết.


3
Chà, tôi thật may mắn khi cần cái này ngay bây giờ chứ không phải hai ngày trước. Cảm ơn; điều đó thật tuyệt!
Asherah

2
Oh my god, cảm ơn bạn. Tôi vừa dành 6 giờ để cố gắng sửa một số thùng rác ở góc trong đó VS không sao chép .dll của một cách thông minh. Đây là câu trả lời thực sự cho cuộc sống, vũ trụ và mọi thứ.
Brandon

5
Đây là giải pháp tốt nhất cho đến nay
PhilHdt

1
Tôi phát hiện ra khi tôi đã thực hiện xong việc này và tải lại dự án trong studio trực quan, các tệp phụ thuộc đã biến mất khỏi trình khám phá giải pháp như thể không có trong dự án. Tuy nhiên, nó vẫn xây dựng như mong đợi và sao chép để xuất ra như mong muốn. Như một công việc xung quanh, tôi hiện đang thêm mỗi tệp hai lần; một lần không có hành động và một lần với thiết lập 'sao chép vào đầu ra'.
Éliette

1
Đây không phải là mục đích sử dụng thẻ này. Trong VS2013, điều này đưa ra cảnh báo khi tải dự án và tệp không hiển thị khi được thêm vào dự án vì nó là thư mục dự án.
jpmc26

15

Tôi tin rằng lệnh XCOPY xử lý các thư mục và tệp tốt hơn. Vì thế,

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

Điều này cho phép tạo các thư mục ngoài thư mục đích.

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

Cấu trúc thư mục / tệp dự án của:

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

Trở thành:

    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

/Dcũng có thể hữu ích, để tránh ghi đè các thay đổi có thể xảy ra.
KurzedMetal

10

Thêm phần sau vào tệp .csproj / .vbproj của bạn

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

Sau đó, thay đổi Hành động xây dựng của bất kỳ tệp nào bạn muốn trong thư mục gốc thành RootContent.


Không phải thông qua các hộp thoại ... nhưng bạn có thể chỉnh sửa dự án của mình trong VS. Nhấp chuột phải vào dự án và chọn Unload Project. Sau đó nhấp chuột phải và chọn Chỉnh sửa. Sau đó, bạn có thể chỉnh sửa tệp MSBuild là dự án của bạn.
Paul Alexander

2
Cảm ơn, điều này có vẻ hữu ích. Thật khó chịu, ngay cả sau khi thêm đoạn mã của bạn vào tệp .vbproj, RootContentkhông hiển thị trong danh sách thả xuống "Hành động xây dựng" và việc nhập theo cách thủ công dẫn đến lỗi "Giá trị thuộc tính không hợp lệ" từ Visual Studio. Tôi đã bỏ lở những gì?
Heinzi

Không hoạt động với dự án Ứng dụng Bảng điều khiển C # Visual Studio 2010.
AMissico

Không hoạt động với dự án Ứng dụng Bảng điều khiển Visual Studio 2010 VB.NET.
AMissico

Không hoạt động với dự án Ứng dụng Bảng điều khiển C # Visual Studio 2008.
AMissico

5

Tôi đã sử dụng điều này trong VS2010, VS2015, VS2017 và VS2019. Tôi thích giải pháp này hơn vì:

  1. XML có thể được sử dụng lại trong bất kỳ dự án nào
  2. "Nội dung gốc" được chọn làm Hành động xây dựng trong giao diện người dùng Visual Studio, giống như bất kỳ "Nội dung" nào khác
  3. "CopyToOutputDirectory" được tuân theo, giống như bạn mong đợi
  4. RootContent được thêm vào đầu ra của dự án: được chuyển qua Project-References, tuân theo "Clean", v.v.
  5. RootContent có thể được chỉ định bằng ký tự đại diện, bảo toàn cấu trúc thư mục đệ quy:
<RootContent Include="common\browserhawk\**">
  <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</RootContent>

Về đầu tệp dự án:

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

Mượn từ câu trả lời này

Sau khi Nhập .targets của Microsoft:

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

Mượn từ câu trả lời này


Điều này là tốt - tôi sẽ hoán đổi từ RootContentngụ ý "mã hóa cứng" CustomContentđể chỉ ra rằng đây là nội dung chuyên biệt mà chúng tôi đang thêm vào dự án này và chúng tôi cần sao chép theo cách cụ thể này. Ngoài ra, tôi cần TargetPath=%(RecursiveDir)%(Filename)%(Extension)tạo lại cấu trúc thư mục từ các CustomContenttệp được chỉ định đến đường dẫn đầu ra.
Jonno

@Jonno Mục tiêu là sao chép (các) tệp trực tiếp vào thư mục đầu ra gốc, bất kể RecursiveDirectory. Hành động xây dựng "Nội dung" được tích hợp sẵn đã cung cấp cho chúng tôi một cơ chế để sao chép trong khi duy trì RecursiveDirectory.
MattGerg

Tôi đã không có cơ hội để kiểm tra điều này trong một thời gian, nhưng sẽ không thiết lập hành động xây dựng "Nội dung" khiến các tệp bên dưới /common/browserhawk/bị sao chép vào /bin/common/browserhawk/như OP đã nói? IIRC, ý định của tôi là đã /common/browserhawk/a.txtkết thúc /bin/a.txtnhưng cho phép đệ quy từ đó xuống, vì vậy /common/browserhawk/secret/stuff.pngcuối cùng đã kết thúc /bin/secret/stuff.png.
Jonno

@Jonno Ok, vâng, điều đó hoàn toàn hợp lý. Tôi đã cập nhật câu trả lời để bao gồm %(RecursiveDirectory). Điều này thực sự thú vị, bởi vì ngoài việc chọn các tệp riêng lẻ trong IDE, bạn cũng có thể chỉ định nhiều tệp bằng các ký tự đại diện. Khi sử dụng **ký tự đại diện, toàn bộ cấu trúc thư mục sẽ được giữ nguyên.
MattGerg

1
Cảm ơn rất nhiều cho câu trả lời tuyệt vời như vậy! Tôi nghĩ rằng câu trả lời này là câu trả lời đúng vì những điều sau đây: 1. Không cmds bên ngoài 2. đa nền tảng
George Anisimov

2

Tôi đã kết thúc việc thêm một bước vào tệp bản dựng không có để sao chép sau khi khen thành công

<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>

2
1 bởi vì đối với một người nào đó sử dụng Nant đây vẫn là một câu trả lời hữu ích
Chris Haines

1

Bạn có thể tạo một tệp hàng loạt để sao chép các tệp và thực thi nó như một sự kiện sau xây dựng.


Tôi đã kết thúc việc này cho một trong những dự án của mình (mặc dù tôi đã sử dụng tập lệnh Python chứ không phải là con dơi).
Fire Lancer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.