คัดลอกไปยัง Output Directory คัดลอกโครงสร้างโฟลเดอร์ แต่ต้องการคัดลอกไฟล์เท่านั้น


87

ฉันมี VS2008 ฉันต้องการคัดลอกไฟล์บางไฟล์จากไดเรกทอรีไปยัง/bin/โฟลเดอร์ของฉัน ฉันได้ตั้งค่าไฟล์ (อยู่ใน/common/browserhawk/) เป็น "Copy to Output Directory" อย่างไรก็ตามมันคัดลอกโครงสร้างโฟลเดอร์ด้วยเช่นกัน: ไฟล์จะถูกคัดลอกไป/bin/common/browserhawk/

ฉันจะคัดลอกไฟล์เหล่านี้ไปเป็นเพียงแค่ได้/bin/อย่างไร ฉันไม่ต้องการเก็บสิ่งเหล่านี้ไว้ในรูทของเว็บไซต์เพื่อให้คัดลอกอย่างถูกต้อง

คำถามที่เกี่ยวข้อง: Visual Studio เพิ่ม. dll และ. pdb ในโปรเจ็กต์หลังจากคอมไพล์

คำตอบ:


59

คุณสามารถเพิ่ม Post Build Event เพื่อคัดลอกไฟล์
ไปที่คุณสมบัติโปรเจ็กต์แท็บสร้างเหตุการณ์และเพิ่มสิ่งต่อไปนี้ในบรรทัดคำสั่งหลังสร้างเหตุการณ์

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

อย่าลืมใส่เครื่องหมายคำพูดหากเส้นทางโครงการของคุณมีช่องว่าง


ขอบคุณสำหรับคำแนะนำนั้นเนื่องจากเพิ่งได้ผลสำหรับฉันใน VS2012 เช่นกัน
Dib

2
ฉันได้แก้ไขสิ่งนี้เล็กน้อยในกรณีของฉัน:xcopy /s /d /y "$(ProjectDir)\stuff" "$(TargetDir)\stuff"
Danny Staple

44

เนื่องจากฉันไม่สามารถแสดงความคิดเห็นเกี่ยวกับคำตอบก่อนหน้านี้ได้ฉันจะวางคำตอบไว้ที่นี่:

การเพิ่มสิ่งที่ @PaulAlexander ให้เพิ่มสิ่งต่อไปนี้ในไฟล์. csproj / .vbproj ของคุณ:

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

สิ่งนี้ช่วยให้คุณสามารถเลือก "RootContent" เป็น Build Action ในหน้าต่าง Properties และทั้งหมดนี้สามารถเข้าถึงได้ผ่าน GUI คำอธิบายที่สมบูรณ์ยิ่งขึ้น: ตัวเลือก "AvailableItemName" โดยพื้นฐานแล้วจะสร้างรายการชื่อใหม่ที่คุณสามารถกำหนดรายการในโปรเจ็กต์ภายใต้คุณสมบัติ "Build Action" ในหน้าต่างคุณสมบัติ จากนั้นคุณสามารถใช้รายการที่สร้างขึ้นใหม่นี้ใน Target ที่คุณต้องการ (เช่นผ่าน "@ (RootContent)")


คำตอบที่ดีเพียงแค่ใช้ตัวเองก็ประสบความสำเร็จ!
Chris Marisic

โปรดทราบว่า VS 2010 (ไม่แน่ใจเกี่ยวกับเวอร์ชันเก่า) จะบ่นAvailableItemNameว่าเป็นองค์ประกอบที่ไม่ถูกต้องหากคุณแก้ไขไฟล์โครงการภายใน VS เพียงแค่เพิกเฉยต่อคำเตือนมันก็ใช้ได้อยู่ดี
Aaronaught

2
น่าเสียดายที่นี่เป็นการคัดลอกไฟล์ลงในไดเร็กทอรีเอาต์พุตของโปรเจ็กต์ที่ไฟล์นั้นเป็นของ - และไม่ได้อยู่ในไดเร็กทอรีเอาต์พุตของโปรเจ็กต์เริ่มต้น นี่เป็นสิ่งสำคัญเมื่อใช้สิ่งนี้ในโครงการห้องสมุด
Sebastian Krysmanski

2
วิธีนี้ใช้งานได้ดีสำหรับการสร้างในโหมดรีลีสและดีบักด้วย vs2008 แต่ดูเหมือนจะไม่ได้ผลเมื่อใช้การเผยแพร่ด้วยคลิกเดียว ข้อเสนอแนะใด ๆ ?
Soenhay

2
ไม่ได้ผลสำหรับฉันใน vs2015 แก้ไขโดยการเขียนเป้าหมายใหม่เล็กน้อย:<Target Name="RootOutputCopyTarget" AfterTargets="Build"> ... </Target>
lorond

44

หากคุณแก้ไข. csproj / .vbproj ในโปรแกรมแก้ไขข้อความคุณสามารถควบคุมตำแหน่งที่จะวางไฟล์ในไดเร็กทอรีเอาต์พุตและชื่อไฟล์ในไดเร็กทอรีเอาต์พุต ตัวอย่างเช่น:

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

นี้จะทำให้ไฟล์ลงในcontent\someContent.txt bin\someContentInOutputDirectory.txtคุณยังสามารถเลือกไดเร็กทอรีย่อยได้binหากต้องการ เพียงแค่เพิ่มเข้าไปในองค์ประกอบลิงก์


3
ว้าวฉันโชคดีที่ต้องการสิ่งนี้ตอนนี้ไม่ใช่สองวันที่ผ่านมา ขอบคุณ; มันเยี่ยมมาก!
Asherah

2
โอ้พระเจ้าขอบคุณ ฉันใช้เวลาเพียง 6 ชั่วโมงในการแก้ไขขยะในมุมที่ VS ไม่ได้คัดลอก. dll ด้วยวิธีที่ชาญฉลาด นี่คือคำตอบที่แท้จริงของชีวิตจักรวาลและทุกสิ่ง
Brandon

5
นี่เป็นทางออกที่ดีที่สุด
PhilHdt

1
ฉันพบว่าเมื่อฉันทำสิ่งนี้แล้วและโหลดโปรเจ็กต์ใหม่ในวิชวลสตูดิโอไฟล์อ้างอิงหายไปจากตัวสำรวจโซลูชันราวกับว่าไม่รวมอยู่ในโปรเจ็กต์ อย่างไรก็ตามมันยังคงสร้างตามที่คาดไว้และคัดลอกไปยังเอาต์พุตตามที่ต้องการ ในการแก้ไขฉันกำลังเพิ่มแต่ละไฟล์สองครั้ง หนึ่งครั้งโดยไม่ต้องดำเนินการใด ๆ และอีกครั้งด้วยการตั้งค่า
Éliette

1
นี่ไม่ใช่การใช้งานแท็กนี้ตามวัตถุประสงค์ ใน VS2013 สิ่งนี้จะแสดงคำเตือนเมื่อโหลดโปรเจ็กต์และมองไม่เห็นไฟล์ที่เพิ่มลงในโปรเจ็กต์เนื่องจากเป็นไดเร็กทอรีโครงการ
jpmc26

15

ฉันเชื่อว่าคำสั่ง XCOPY จัดการไดเร็กทอรีและไฟล์ได้ดีกว่า ดังนั้น,

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

ซึ่งอนุญาตให้สร้างโฟลเดอร์จากไดเร็กทอรีเป้าหมาย

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

โฟลเดอร์ Project / โครงสร้างไฟล์ของ:

    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อาจมีประโยชน์เช่นกันเพื่อหลีกเลี่ยงการเขียนทับการเปลี่ยนแปลงที่เป็นไปได้
KurzedMetal

10

เพิ่มสิ่งต่อไปนี้ในไฟล์. csproj / .vbproj ของคุณ

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

จากนั้นเปลี่ยน Build Action ของไฟล์ใด ๆ ที่คุณต้องการในโฟลเดอร์รูทเป็น RootContent


ไม่ผ่านกล่องโต้ตอบ ... แต่คุณสามารถแก้ไขโครงการของคุณใน VS. คลิกขวาที่โปรเจ็กต์แล้วเลือกยกเลิกการโหลดโปรเจ็กต์ จากนั้นคลิกขวาและเลือกแก้ไข จากนั้นคุณสามารถแก้ไขไฟล์ MSBuild ที่เป็นโครงการของคุณ
Paul Alexander

2
ขอบคุณสิ่งนี้มีประโยชน์ โชคไม่ดีที่แม้ว่าหลังจากเพิ่มข้อมูลโค้ดของคุณไปยังไฟล์. vbproj แล้วRootContentจะไม่ปรากฏในรายการแบบเลื่อนลง "Build Action" และการป้อนข้อมูลด้วยตนเองทำให้เกิดข้อผิดพลาด "ค่าคุณสมบัติไม่ถูกต้อง" จาก Visual Studio ฉันพลาดอะไร?
Heinzi

ไม่ทำงานกับโครงการ Visual Studio 2010 C # Console Application
AMissico

ไม่ทำงานกับโครงการ Visual Studio 2010 VB.NET Console Application
AMissico

ไม่ทำงานกับโครงการ Visual Studio 2008 C # Console Application
AMissico

5

ฉันใช้สิ่งนี้ใน VS2010, VS2015, VS2017 และ VS2019 ฉันชอบวิธีนี้เพราะ:

  1. XML สามารถใช้ซ้ำได้ในทุกโปรเจ็กต์
  2. "RootContent" ถูกเลือกให้เป็น Build Action ใน Visual Studio UI เช่นเดียวกับ "เนื้อหา" อื่น ๆ
  3. "CopyToOutputDirectory" เป็นไปตามที่คุณคาดหวัง
  4. มีการเพิ่ม RootContent ลงในผลลัพธ์ของโครงการ: ดำเนินการผ่านการอ้างอิงโครงการปฏิบัติตาม "Clean" เป็นต้น
  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>

ยืมมาจากคำตอบนี้

หลังจากนำเข้า 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>

ยืมมาจากคำตอบนี้


นี่เป็นสิ่งที่ดี - ฉันจะเปลี่ยนคำRootContentที่มีนัยว่า "ฮาร์ดโค้ด" เพื่อCustomContentระบุว่านี่เป็นเนื้อหาพิเศษที่เรากำลังเพิ่มในโปรเจ็กต์นี้และเราจำเป็นต้องคัดลอกด้วยวิธีนี้โดยเฉพาะ นอกจากนี้ฉันต้องTargetPath=%(RecursiveDir)%(Filename)%(Extension)สร้างโครงสร้างโฟลเดอร์ใหม่จากCustomContentไฟล์ที่ระบุไปยังเส้นทางเอาต์พุต
Jonno

@ จอนโนเป้าหมายคือการคัดลอกไฟล์ไปยังไดเร็กทอรีเอาต์พุตรากโดยตรงโดยไม่คำนึงถึง RecursiveDirectory บิวด์แอ็คชั่น "เนื้อหา" ในตัวมีกลไกในการคัดลอกอยู่แล้วในขณะที่ยังคงรักษา RecursiveDirectory
MattGerg

ฉันไม่ได้มีโอกาสทดสอบสิ่งนี้มาระยะหนึ่งแล้ว แต่การไม่ตั้งค่าการสร้าง "เนื้อหา" ทำให้ไฟล์/common/browserhawk/ถูกคัดลอกไป/bin/common/browserhawk/ตามที่ OP กล่าวไว้หรือไม่ IIRC ความตั้งใจของฉันคือต้อง/common/browserhawk/a.txtจบลง/bin/a.txtแต่อนุญาตให้มีการเรียกซ้ำจากที่นั่นลงมาจึง/common/browserhawk/secret/stuff.pngลงเอยด้วย/bin/secret/stuff.png.
Jonno

@ จอนโนโอเคใช่ตอนนี้มันสมเหตุสมผลแล้ว ฉันอัปเดตคำตอบเพื่อรวมไฟล์%(RecursiveDirectory). นี่เป็นสิ่งที่ยอดเยี่ยมจริงๆเพราะนอกจากการเลือกไฟล์แต่ละไฟล์ใน IDE แล้วคุณยังสามารถระบุไฟล์หลายไฟล์ด้วยสัญลักษณ์แทน เมื่อใช้**สัญลักษณ์แทนโครงสร้างโฟลเดอร์ทั้งหมดจะถูกรักษาไว้
MattGerg

1
ขอบคุณมากสำหรับคำตอบที่ยอดเยี่ยม! ฉันคิดว่าคำตอบนี้เป็นคำตอบที่ถูกต้องเนื่องจากสิ่งต่อไปนี้: 1. ไม่มี cmds ภายนอก 2. แพลตฟอร์มข้าม
George Anisimov

2

ฉันลงเอยด้วยการเพิ่มขั้นตอนในไฟล์ nant build เพื่อคัดลอกหลังจากปฏิบัติตามสำเร็จ

<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 เพราะสำหรับคนที่ใช้ nant นี่ยังคงเป็นคำตอบที่เป็นประโยชน์
Chris Haines

1

คุณสามารถสร้างไฟล์แบตช์เพื่อคัดลอกไฟล์และเรียกใช้งานเป็นเหตุการณ์หลังการสร้าง


ฉันลงเอยด้วยการทำสิ่งนี้สำหรับหนึ่งในโครงการของฉัน (แม้ว่าฉันจะใช้สคริปต์ Python แทนค้างคาว)
Fire Lancer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.