【问题标题】:Best way to concatenate plain text files?连接纯文本文件的最佳方法?
【发布时间】:2011-07-23 05:02:53
【问题描述】:

我有一大堆纯文本文件,命名如下:file1.txt、file2.txt、...、file14.txt、... 我想将它们按正确顺序连接到一个 .txt 文件。 我应该如何以编程方式执行此操作? 在命令窗口中运行的批处理文件? 还是编写一个 Windows 控制台应用程序?

无论如何,我可以得到代码吗?谢谢。

更多信息:

  • 大量文件。每次我做这个报告时都会有一百个或更多。

  • dir 不会以正确的顺序给出文件:例如 file10.txt 出现在 file2.txt 之前,这就是我强调的原因。从 1 到 n 连接到文件名前缀的 for i 似乎是最好的。但我不知道如何在批处理模式下或从 Windows 程序执行命令。

我倾向于做一个 Windows 控制台应用程序。这样的事情会奏效吗?

class Program
{
    static void Main(string[] args)
    {
        string strCmdLine;
        System.Diagnostics.Process process1;
        process1 = new System.Diagnostics.Process();


        Int16 n = Convert.ToInt16(args[1]);
        int i;
        for (i = 1; i < n; i++)
        {
            strCmdLine = "/C copy more work here " + args[0] + i.ToString();
            System.Diagnostics.Process.Start("CMD.exe", strCmdLine);
            process1.Close();
        }


    }
}

【问题讨论】:

  • 您有大量的小文件吗?少量大文件?两者都有一点?
  • -1 表示“我能拿到代码吗?”
  • 这是一次性的吗?如果是这样,只需copy file1.txt+file2.txt+file3.txt+and.so.on.txt destination.txt
  • 这里似乎有一个隐藏的挑战:如果文件按照他所说的那样命名,那么按照正确的顺序排列它们需要手动排序(正如@Michael Burr 建议的那样)或StrCmpLogicalW (这是资源管理器的排序方式),因为如果数字

标签: .net windows command-line windows-console


【解决方案1】:

不是最有效的代码,但你应该能明白:

        Dim files As String()
    Dim tempFile As String
    Dim orderedFiles As New Dictionary(Of Int32, String)
    Dim fileNumber As Int32
    Dim filePos As Int32
    Dim dotTxtPos As Int32
    Dim fileData As String
    Const CONST_DEST_FILE As String = "c:\tempfiles\destination.txt"

    files = System.IO.Directory.GetFiles("c:\tempfiles", "file*.txt")

    For Each tempFile In files
        If tempFile.ToLower.Contains("\file") = False Or tempFile.ToLower.Contains(".txt") = False Then
            Continue For
        End If

        filePos = tempFile.ToLower.IndexOf("\file") + 5
        dotTxtPos = tempFile.ToLower.IndexOf(".txt", filePos)
        If Int32.TryParse(tempFile.ToLower.Substring(filePos, dotTxtPos - filePos), fileNumber) = True Then
            orderedFiles.Add(fileNumber, tempFile)
        End If
    Next

    If System.IO.File.Exists(CONST_DEST_FILE) = True Then
        System.IO.File.Delete(CONST_DEST_FILE)
    End If

    fileNumber = 0
    Do While orderedFiles.Count > 0
        fileNumber += 1
        If orderedFiles.ContainsKey(fileNumber) = True Then
            tempFile = orderedFiles(fileNumber)
            fileData = System.IO.File.ReadAllText(tempFile)
            System.IO.File.AppendAllText(CONST_DEST_FILE, fileData)
            orderedFiles.Remove(fileNumber)
        End If
    Loop

【讨论】:

  • 你在说多少个文件?告诉我,我会写一些处理它的代码。
  • 我每次做报告都会有一百多个文件。我需要做大约 20 份这样的报告。
  • Joey,使用相同的文件作为输入和输出,它工作得很好,但如果该文件不是复制文件列表中的第一个文件,则可能会产生奇怪的结果。
  • @Robert:考虑到它可以在三行中完成,那是非常多的代码......
【解决方案2】:

如果你在 Windows 上,安装 cygwin 以便你可以拥有一个 bash shell,然后:

对于 {1..N} 中的 i ;做 cat ${1}.txt >> all.txt ;完成

其中 N 是您拥有的文件数,这些文件将全部连接在 all.txt 中

【讨论】:

  • 该死的错字! ${1}.txt 中的 1 应该是 "i" --> ${i}.txt
【解决方案3】:

如果您愿意投入最少的时间,这应该会很有效。对于一个完全自动化的过程,您需要计算出文件的数量(这并不难,但我从这里省略了)。但对于仅 20 份报告,这可能就可以了。

此外,批处理文件中的过程不是最佳的。事实上,这很可怕。我认为是 O( n !)。使用批处理文件下面的版本可能会好得多。

作为批处理文件:

@echo off
if not "%~1"=="" goto begin
echo Usage: %~n1 ^<N^>
echo where ^<N^> is the highest number that occurs in the file name.
goto :eof

:begin
set N=%~1
rem create empty file
copy nul temp.txt
rem just loop from 1 to N
for /l %%x in (1,1,%N%) do call :concat %%x
rename temp.txt result.txt
goto :eof

:concat
  copy temp.txt+file%1.txt temp2.txt
  move /y temp2.txt temp.txt
goto :eof

未经测试,但它非常简单,所以我怀疑其中有太多错误。

或者,我只是认为以下操作会更容易(在命令行上):

(for /l %x in (1,1,N) do type file%x.txt) > result.txt

只需将N 替换为您拥有的最高后缀即可。

【讨论】:

    【解决方案4】:

    您有几种可能性。如果您在命令行中执行dir,并且它们按照您想要的顺序显示,那么事情就很简单了——您可以执行以下操作:

    copy file*.txt destination.txt
    

    这会产生一些小的副作用——它会在遇到第一个control-Z 时停止读取任何给定文件,并且会在文件末尾附加一个control-Z。如果您不希望这些情况发生,可以添加/b:

    copy /b file*.txt destination.txt
    

    如果“目录”顺序不是您想要的顺序,那么您可以执行以下操作:

    for %c in (a.txt b.txt c.txt) copy destination.txt+%c
    

    其中a.txt、b.txt、c.txt(等)是您要复制的文件,按照您要复制的顺序列出(而且,很明显,destination.txt 是您要提供的名称到您将它们全部放在一起的结果。或者,您可以在一个命令行中将它们全部列出,例如copy a.txt+b.txt+c.txt destination.txt。

    【讨论】:

      【解决方案5】:

      这可以通过以下 Windows PowerShell 单行来完成(为了便于阅读,在此处展开​​四行):

      Get-ChildItem -Filter "*.txt" | 
          Sort-Object { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) } | 
          gc | 
          sc result.txt
      

      Get-ChildItem 检索文件名,但它们的顺序错误(按 ASCII 顺序而非字母顺序排序)。

      Sort-Object cmdlet 用于按您指定的文件名排序,方法是在比较文件名之前填充文件名中的数字。

      gc 是Get-Content 的别名,它读取所有输入文件的内容。

      sc 是Set-Content 的别名,将结果写入指定文件。


      这是使用 C# 的另一种方法,以防您不能/不会使用 PowerShell:

      static class Program
      {
          [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
          static extern int StrCmpLogicalW(string s1, string s2);
      
          static void Main()
          {
              string[] files = Directory.GetFiles(@"C:\Path\To\Files", "*.txt");
              Array.Sort(files, StrCmpLogicalW);
              File.WriteAllLines("result.txt", files.SelectMany(file => File.ReadLines(file)));
          }
      }
      

      这使用StrCmpLogicalW 函数以正确的顺序获取文件名(该函数实际上是Windows Explorer 用来对文件名进行排序的函数)。

      【讨论】:

      • @Joey:如果文件名只有一个数字,否则所有文件名都相同,是的。
      【解决方案6】:

      在命令提示符下,你可以执行, type *.txt &gt; destination.txt

      注意:这也会连接子目录下的文本文件

      【讨论】:

        【解决方案7】:

        我记得一个非常有用的程序:split & concat。对于mac os x ...不知道是否有其他操作系统版本...可以正常工作! http://loekjehe.home.xs4all.nl/Split&Concat/

        【讨论】:

        • 不,这仅适用于 OS X -- 没有 Windows 版本。
        猜你喜欢
        • 2011-01-28
        • 2014-06-17
        • 2010-09-06
        • 1970-01-01
        • 1970-01-01
        • 2023-03-26
        • 1970-01-01
        • 2014-02-19
        • 2018-12-03
        相关资源
        最近更新 更多