Лучший способ объединить простые текстовые файлы?

У меня есть целая куча простых текстовых файлов, названных следующим образом: file1.txt, file2.txt, ..., file14.txt, ... Я хочу объединить их все в правильном порядке в один файл.txt. Как мне сделать это программно? Пакетный файл работает в командном окне? Или написать консольное приложение Windows?

В любом случае, могу ли я получить код? Благодарю.

Больше информации:

  • большое количество файлов. Сотня или больше каждый раз, когда я делаю этот отчет.

  • dir не даст файлы в правильной последовательности: например, file10.txt появляется перед file2.txt, поэтому я делаю упор. Кажется, для i от 1 до n конкатенированный с префиксом имени файла является лучшим. Но я не знаю, как это сделать в пакетном режиме или выполнить команду из программы 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();
        }


    }
}

7 ответов

Решение

Это должно хорошо работать, если вы готовы потратить минимум времени. Для полностью автоматизированного процесса вам необходимо определить количество файлов (что не так сложно, но я здесь опущен). Но для всего 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 с самым высоким суффиксом у вас есть.

Не самый эффективный код, но у вас должна получиться идея:

        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

Если вы работаете в Windows, установите Cygwin, чтобы иметь оболочку bash, а затем:

для меня в {1..N}; do cat ${1}.txt >> all.txt; сделанный

Где N - это количество файлов, которые у вас есть. Все файлы будут объединены в all.txt.

Это можно сделать с помощью следующей оболочки 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 Командлет используется для сортировки имен файлов, как вы указали, добавляя числа в имени файла перед сравнением имен.

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 использует для сортировки имен файлов).

У вас есть несколько возможностей. Если вы делаете 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,

В командной строке вы можете выполнить,type *.txt > destination.txt

Примечание: это также объединяет текстовые файлы в подкаталогах

Я помню одну очень полезную программу: split & concat. для Mac OS X... не знаю, была ли другая версия ОС... работает! http://loekjehe.home.xs4all.nl/Split&Concat/

Другие вопросы по тегам