Copiar para o diretório de saída copia a estrutura da pasta, mas deseja apenas copiar os arquivos


87

Eu tenho um VS2008 e desejo copiar certos arquivos de um diretório para minha /bin/pasta. Eu defini os arquivos (localizados em /common/browserhawk/) como "Copiar para o diretório de saída". No entanto, ele copia a estrutura de pastas também: os arquivos são copiados para/bin/common/browserhawk/

Como faço para copiar esses arquivos para o Just /bin/? Não desejo armazená-los na raiz do site para que sejam copiados corretamente.

Pergunta relacionada: Visual Studio adiciona .dll e .pdb ao projeto após a compilação

Respostas:


59

Você pode adicionar um evento Post Build para copiar os arquivos.
Acesse as propriedades do projeto, guia Build Events e adicione o seguinte à linha de comando do evento Post-build:

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

Certifique-se de incluir as aspas se o caminho do projeto contiver espaços.


Obrigado por esse conselho, já que funcionou para mim também no VS2012.
Dib

2
Eu modifiquei um pouco no meu caso:xcopy /s /d /y "$(ProjectDir)\stuff" "$(TargetDir)\stuff"
Danny Staple

44

Como não posso comentar as respostas anteriores, colocarei a solução aqui:

Adicionando ao que @PaulAlexander forneceu, adicione o seguinte ao seu arquivo .csproj / .vbproj:

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

Isso permite que você selecione "RootContent" como a ação de construção na janela Propriedades, e tudo pode ser acessado por meio da GUI. Uma explicação mais completa: a opção "AvailableItemName" basicamente cria uma nova lista nomeada à qual você pode atribuir itens no projeto sob a propriedade "Build Action" na janela Properties. Você pode então usar essa lista recém-criada em qualquer destino que desejar (por exemplo, via "@ (RootContent)").


Boa resposta, acabei de usar isso para ter sucesso!
Chris Marisic

Observe também que o VS 2010 (não tenho certeza sobre as versões anteriores) reclamará por AvailableItemNameser um elemento inválido se você editar o arquivo de projeto no VS; apenas ignore o aviso, ele funciona de qualquer maneira.
Aaronaught,

2
Infelizmente, isso apenas copia o arquivo no diretório de saída do projeto ao qual o arquivo pertence - e não no diretório de saída do projeto de inicialização. Isso é importante ao usar isso em um projeto de biblioteca.
Sebastian Krysmanski,

2
Isso funciona muito bem para compilar no modo de liberação e depuração com o vs2008, mas não parece funcionar ao usar a publicação com um clique. Alguma sugestão?
Soenhay,

2
Não funcionou para mim no vs2015. Corrigido reescrevendo o alvo um pouco: <Target Name="RootOutputCopyTarget" AfterTargets="Build">... </Target>
lorond

44

Se você editar .csproj / .vbproj em um editor de texto, poderá controlar onde o arquivo é colocado no diretório de saída e também qual nome o arquivo terá no diretório de saída. Por exemplo:

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

Isso colocará o arquivo content\someContent.txtem bin\someContentInOutputDirectory.txt. Você também pode escolher um subdiretório, binse desejar; basta adicioná-lo ao elemento Link.


3
Uau, tive sorte de precisar disso agora e não há dois dias. Obrigado; isso é ótimo!
Asherah de

2
Ai meu Deus, obrigada. Acabei de passar 6 horas tentando consertar algum lixo de canto em que o VS não estava copiando .dll de uma forma inteligente. Esta é a verdadeira resposta para a vida, o universo e tudo.
Brandon

5
Esta é de longe a melhor solução
PhilHdt

1
Descobri que, depois de fazer isso e recarregar o projeto no Visual Studio, os arquivos de dependência desapareceram do gerenciador de soluções como se não estivessem incluídos no projeto. No entanto, ele ainda constrói conforme o esperado e copia para a saída conforme desejado. Como uma solução alternativa, estou atualmente adicionando cada arquivo duas vezes; uma vez sem ação e uma vez com 'copiar para saída' definido.
Éliette

1
Este não é o uso pretendido para esta tag. No VS2013, isso emite um aviso ao carregar o projeto, e o arquivo não é visível quando adicionado ao projeto porque é o diretório do projeto.
jpmc26

15

Acredito que o comando XCOPY lida melhor com diretórios e arquivos. Portanto,

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

O que permite a criação de pastas fora do diretório de destino.

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

A pasta do projeto / estrutura de arquivos de:

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

Torna-se:

    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

/Dtambém pode ser útil, para evitar a substituição de possíveis alterações.
KurzedMetal

10

Adicione o seguinte ao seu arquivo .csproj / .vbproj

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

Em seguida, altere a Build Action de quaisquer arquivos que você deseja na pasta raiz para RootContent.


Não através das caixas de diálogo ... mas você pode editar seu projeto no VS. Clique com o botão direito do mouse no projeto e selecione Descarregar projeto. Em seguida, clique com o botão direito e selecione Editar. Em seguida, você pode editar o arquivo MSBuild que é o seu projeto.
Paul Alexander

2
Obrigado, isso parece útil. Infelizmente, mesmo depois de adicionar seu snippet ao arquivo .vbproj, RootContentele não aparece na lista suspensa "Build Action" e inseri-lo manualmente resulta em um erro "Property value not valid" do Visual Studio. O que eu perdi?
Heinzi

Não funciona com o projeto Visual Studio 2010 C # Console Application.
AMissico

Não funciona com o projeto Visual Studio 2010 VB.NET Console Application.
AMissico

Não funciona com o projeto Visual Studio 2008 C # Console Application.
AMissico

5

Eu usei isso no VS2010, VS2015, VS2017 e VS2019. Eu prefiro esta solução porque:

  1. O XML é reutilizável em qualquer projeto
  2. O "RootContent" é escolhido como uma ação de construção na interface do usuário do Visual Studio, assim como qualquer outro "conteúdo"
  3. O "CopyToOutputDirectory" é obedecido, assim como você esperaria
  4. O RootContent é adicionado à saída do projeto: é realizado através de Referências do Projeto, obedece a "Limpar", etc.
  5. O RootContent pode ser especificado com um caractere curinga, preservando a estrutura da pasta recursiva:
<RootContent Include="common\browserhawk\**">
  <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</RootContent>

Perto do início do arquivo de projeto:

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

Emprestado desta resposta

Após a importação do 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>

Emprestado desta resposta


Isso é bom - eu trocaria o RootContentque significa "hard coded" para CustomContentindicar que este é o conteúdo especializado que estamos adicionando a este projeto e que precisamos copiar dessa maneira particular. Também como um aparte, eu precisei TargetPath=%(RecursiveDir)%(Filename)%(Extension)recriar a estrutura de pastas dos CustomContentarquivos especificados para o caminho de saída.
Jonno

@Jonno O objetivo é copiar o (s) arquivo (s) diretamente para o diretório de saída raiz, independentemente do RecursiveDirectory. A ação de compilação "Conteúdo" embutida já nos fornece um mecanismo para copiar enquanto mantém o RecursiveDirectory.
MattGerg de

Não tenho a chance de testar isso há algum tempo, mas definir a ação de construção "Conteúdo" não faria com que os arquivos em /common/browserhawk/sejam copiados /bin/common/browserhawk/como o OP disse? IIRC, minha intenção era /common/browserhawk/a.txtterminar em, /bin/a.txtmas permitir a recursão de lá para baixo, então /common/browserhawk/secret/stuff.pngacaba em /bin/secret/stuff.png.
Jonno

@Jonno Ok, sim, agora faz todo o sentido. Eu atualizei a resposta para incluir o %(RecursiveDirectory). Isso é muito legal, porque além de selecionar arquivos individuais no IDE, você também pode especificar vários arquivos com curingas. Ao usar o **curinga, toda a estrutura da pasta será preservada.
MattGerg

1
Muito obrigado por essa ótima resposta! Acho que esta resposta é a correta devido ao seguinte: 1. Sem cmds externos 2. plataforma cruzada
George Anisimov

2

Acabei adicionando uma etapa ao arquivo de compilação nant para copiar após a conclusão bem-sucedida

<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 porque para alguém que usa o nant, esta ainda é uma resposta útil
Chris Haines

1

Você pode construir um arquivo em lote para copiar os arquivos e executá-lo como um evento pós-construção.


Acabei fazendo isso para um dos meus projetos (embora tenha usado um script Python em vez de um morcego).
Fire Lancer,
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.