Лучший способ объединить простые текстовые файлы? - PullRequest
0 голосов
/ 23 июля 2011

У меня есть целая куча простых текстовых файлов, названных следующим образом: 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 ]

2 голосов
/ 02 сентября 2011

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

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

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

2 голосов
/ 23 июля 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
1 голос
/ 23 июля 2011

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

1 голос
/ 23 июля 2011

Это можно сделать с помощью следующего вкладыша Windows PowerShell (для удобства чтения он разделен на четыре строки):

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

Get-ChildItem извлекает имена файлов, но они будут в неправильном порядке (сортировать ASCIIbetically, а не по алфавиту).

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

1 голос
/ 23 июля 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.

0 голосов
/ 18 ноября 2015

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

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

0 голосов
/ 23 июля 2011

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

...