Copia nella directory di output copia la struttura delle cartelle ma desidera solo copiare i file


87

Ho un VS2008 e voglio copiare determinati file da una directory nella mia /bin/cartella. Ho impostato i file (che si trovano in /common/browserhawk/) su "Copia nella directory di output". Tuttavia, copia anche la struttura delle cartelle: i file vengono copiati in/bin/common/browserhawk/

Come faccio a copiare questi file solo /bin/? Non voglio memorizzarli nella directory principale del sito Web per copiarli correttamente.

Domanda correlata: Visual Studio aggiunge .dll e .pdb al progetto dopo la compilazione

Risposte:


59

Puoi aggiungere un evento di post build per copiare i file.
Vai alle proprietà del progetto, scheda Eventi di compilazione e aggiungi quanto segue alla riga di comando dell'evento di post-compilazione:

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

Assicurati di includere le virgolette se il percorso del tuo progetto contiene spazi.


Grazie per questo consiglio, perché ha funzionato anche per me in VS2012.
Dib

2
L'ho modificato leggermente nel mio caso:xcopy /s /d /y "$(ProjectDir)\stuff" "$(TargetDir)\stuff"
Danny Staple

44

Poiché non posso commentare le risposte precedenti, inserirò la soluzione qui:

Aggiungendo a quanto fornito da @PaulAlexander, aggiungi quanto segue al tuo file .csproj / .vbproj:

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

Ciò consente di selezionare "RootContent" come Azione di compilazione nella finestra Proprietà ed è possibile accedere a tutti tramite la GUI. Una spiegazione più completa: l'opzione "AvailableItemName" crea fondamentalmente un nuovo elenco con nome a cui è possibile assegnare elementi nel progetto sotto la proprietà "Build Action" nella finestra Proprietà. È quindi possibile utilizzare questo elenco appena creato in qualsiasi destinazione che ti piace (ad esempio tramite "@ (RootContent)").


Bella risposta, l'ho usata io stessa per il successo!
Chris Marisic

Si noti inoltre che VS 2010 (non sicuro delle versioni precedenti) si lamenterà di AvailableItemNameessere un elemento non valido se si modifica il file di progetto all'interno di VS; ignora l'avvertimento, funziona comunque.
Aaronaught

2
Sfortunatamente, questo copia il file solo nella directory di output del progetto a cui appartiene il file e non nella directory di output del progetto di avvio. Questo è importante quando lo si utilizza in un progetto di libreria.
Sebastian Krysmanski

2
Funziona alla grande per la creazione in modalità di rilascio e debug con vs2008 ma non sembra funzionare quando si utilizza la pubblicazione con un clic. Eventuali suggerimenti?
Soenhay

2
Non ha funzionato per me nel vs2015. Risolto il <Target Name="RootOutputCopyTarget" AfterTargets="Build">
problema

44

Se modifichi .csproj / .vbproj in un editor di testo, puoi controllare dove si trova il file nella directory di output e anche quale nome avrà il file nella directory di output. Per esempio:

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

Questo metterà il file content\someContent.txtin bin\someContentInOutputDirectory.txt. Puoi anche scegliere una sottodirectory binse vuoi; aggiungilo semplicemente all'elemento Link.


3
Wow, sono stato fortunato ad averne bisogno adesso e non due giorni fa. Grazie; questo è fantastico!
Asherah

2
Oh mio Dio, grazie. Ho appena passato 6 ore a cercare di riparare alcuni rifiuti in un angolo dove VS non stava copiando .dll in modo intelligente. Questa è la vera risposta alla vita, all'universo ea tutto.
Brandon

5
Questa è di gran lunga la soluzione migliore
PhilHdt

1
Ho scoperto che dopo aver eseguito questa operazione e ricaricato il progetto in Visual Studio, i file delle dipendenze sono scomparsi da Esplora soluzioni come se non fossero inclusi nel progetto. Tuttavia, viene comunque compilato come previsto e copia nell'output come desiderato. Per ovviare al problema, attualmente sto aggiungendo ogni file due volte; una volta senza alcuna azione e una volta con "copia nell'output" impostato.
Éliette

1
Questo non è l'uso previsto di questo tag. In VS2013, questo genera un avviso durante il caricamento del progetto e il file non è visibile come aggiunto al progetto perché è la directory del progetto.
jpmc26

15

Credo che il comando XCOPY gestisca meglio directory e file. Perciò,

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

Che consente di creare cartelle fuori dalla directory di destinazione.

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

La struttura cartella / file del progetto di:

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

Diventa:

    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

/Dpuò essere utile anche per evitare di sovrascrivere eventuali modifiche.
KurzedMetal

10

Aggiungi quanto segue al tuo file .csproj / .vbproj

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

Quindi modifica l'azione di compilazione di tutti i file che desideri nella cartella principale in RootContent.


Non attraverso le finestre di dialogo ... ma puoi modificare il tuo progetto in VS. Fare clic con il pulsante destro del mouse sul progetto e selezionare Scarica progetto. Quindi fare clic con il tasto destro e selezionare Modifica. Quindi puoi modificare il file MSBuild che è il tuo progetto.
Paul Alexander,

2
Grazie, sembra utile. Sfortunatamente, anche dopo aver aggiunto lo snippet al file .vbproj, RootContentnon viene visualizzato nell'elenco a discesa "Build Action" e inserendolo manualmente si ottiene un errore "Property value not valid" da Visual Studio. Cosa mi sono perso?
Heinzi

Non funziona con il progetto di applicazione console C # di Visual Studio 2010.
AMissico

Non funziona con il progetto di applicazione console VB.NET di Visual Studio 2010.
AMissico

Non funziona con il progetto di applicazione console C # di Visual Studio 2008.
AMissico

5

L'ho usato in VS2010, VS2015, VS2017 e VS2019. Preferisco questa soluzione perché:

  1. L'XML è riutilizzabile in qualsiasi progetto
  2. "RootContent" viene scelto come azione di compilazione nell'interfaccia utente di Visual Studio, proprio come qualsiasi altro "Contenuto"
  3. La "CopyToOutputDirectory" viene rispettata, proprio come ci si aspetterebbe
  4. Il RootContent viene aggiunto all'output del progetto: viene eseguito attraverso Project-References, obbedisce a "Clean", ecc.
  5. Il RootContent può essere specificato con un carattere jolly, preservando la struttura delle cartelle ricorsive:
<RootContent Include="common\browserhawk\**">
  <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</RootContent>

Verso l'inizio del file di progetto:

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

Preso in prestito da questa risposta

Dopo l'importazione di 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>

Preso in prestito da questa risposta


Questo va bene, lo cambierei RootContent che implica "hard coded" per CustomContentindicare che si tratta di contenuto specializzato che stiamo aggiungendo a questo progetto e che dobbiamo copiare in questo modo particolare. Inoltre, per inciso, avevo bisogno TargetPath=%(RecursiveDir)%(Filename)%(Extension)di ricreare la struttura delle cartelle dai CustomContentfile specificati al percorso di output.
Jonno

@Jonno L'obiettivo è copiare i file direttamente nella directory di output principale, indipendentemente da RecursiveDirectory. L'azione build "Content" incorporata ci fornisce già un meccanismo per copiare mantenendo la RecursiveDirectory.
MattGerg

Non ho avuto la possibilità di testarlo per un po ', ma l'impostazione dell'azione di compilazione "Contenuto" non causerebbe la /common/browserhawk/copia dei file sotto /bin/common/browserhawk/come ha detto l'OP? IIRC, la mia intenzione era di /common/browserhawk/a.txtfinire dentro /bin/a.txtma permettere la ricorsione da lì in basso, quindi /common/browserhawk/secret/stuff.pngfinisce dentro /bin/secret/stuff.png.
Jonno

@ Jonno Ok, sì, ora ha perfettamente senso. Ho aggiornato la risposta per includere il file%(RecursiveDirectory) . Questo è davvero interessante, perché oltre a selezionare singoli file nell'IDE, puoi anche specificare più file con caratteri jolly. Quando si utilizza il **carattere jolly, l'intera struttura delle cartelle verrà preservata.
MattGerg

1
Grazie mille per questa ottima risposta! Penso che questa risposta sia la risposta giusta per i seguenti motivi: 1. Nessun cmd esterno 2. multipiattaforma
George Anisimov

2

Ho finito per aggiungere un passaggio al file di build nant da copiare dopo la compilazione riuscita

<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 perché per qualcuno che usa nant questa è ancora una risposta utile
Chris Haines

1

È possibile creare un file batch per copiare i file ed eseguirlo come evento di post-compilazione.


Ho finito per farlo per uno dei miei progetti (anche se ho usato uno script Python piuttosto che un pipistrello).
Fire Lancer
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.