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

Steve Wright
fonte

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.

Bill A.
fonte
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)").

onda de choque
fonte
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.

Daniel Yankowsky
fonte
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
AMissico
fonte
/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.

Paul Alexander
fonte
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

MattGerg
fonte
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>
Steve Wright
fonte
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.

jvanderh
fonte
Acabei fazendo isso para um dos meus projetos (embora tenha usado um script Python em vez de um morcego).
Fire Lancer,