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

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

В любом случае, можно код? Спасибо.

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

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

  • dir не будет давать файлы в правильной последовательности: например, файл10.txt появляется перед файлом2.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();
        }


    }
}

person user776676    schedule 23.07.2011    source источник
comment
У вас есть большое количество мелких файлов? Небольшое количество больших файлов? Немного того и другого?   -  person Brad    schedule 23.07.2011
comment
-1 за «могу ли я получить код?»   -  person shelman    schedule 23.07.2011
comment
Это одноразовая вещь? Если да, то просто copy file1.txt+file2.txt+file3.txt+and.so.on.txt destination.txt   -  person Michael Burr    schedule 23.07.2011
comment
Кажется, здесь есть скрытая проблема: если файлы названы так, как он говорит, то для их правильного порядка потребуется либо упорядочить их вручную (как предлагает @Michael Burr), либо StrCmpLogicalW (как сортирует проводник), как Командная строка не будет правильно сортировать числа, если число ‹10 не будет заполнено нулями.   -  person Sven    schedule 23.07.2011


Ответы (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 самым высоким суффиксом, который у вас есть.

person Joey    schedule 23.07.2011

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

        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
person Robert Beaubien    schedule 23.07.2011
comment
Сколько файлов вы здесь говорите? Дайте мне знать, и я напишу код, который это обрабатывает. - person Robert Beaubien; 23.07.2011
comment
Более сотни файлов каждый раз, когда я делаю отчет. И мне нужно сделать около 20 отчетов, подобных этому. - person user776676; 23.07.2011
comment
Джоуи, он отлично работает, используя один и тот же файл в качестве ввода и вывода, но может иметь странные результаты, если этот файл не находится первым в списке скопированных файлов. - person Robert Beaubien; 23.07.2011
comment
@Robert: это ужасно много кода, учитывая, что его можно сделать в три строки... - person Sven; 23.07.2011

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

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

Где N — количество имеющихся у вас файлов. Все файлы будут объединены в файл all.txt.

person jjk    schedule 02.09.2011
comment
блин - опечатка! 1 внутри ${1}.txt должно быть i --› ${i}.txt - person jjk; 02.09.2011

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

person Jerry Coffin    schedule 23.07.2011

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


Вот альтернативный подход с использованием С#, если вы не можете/не будете использовать 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 для сортировки имен файлов).

person Sven    schedule 23.07.2011
comment
@Joey: если имя файла имеет только один номер, а в остальном все имена файлов одинаковы, да. - person Sven; 23.07.2011

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

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

person nachiappanpl    schedule 18.11.2015

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

person H_7    schedule 23.07.2011
comment
Нет, это только OS X, а не версия для Windows. - person Gabe; 23.07.2011