Най-добрият начин за свързване на обикновени текстови файлове?

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

Така или иначе, мога ли да получа кода? Благодаря.

Повече информация:

  • голям брой файлове. Сто или повече всеки път, когато правя този доклад.

  • dir няма да даде файловете в правилна последователност: file10.txt се появява преди file2.txt например, затова наблягам. Изглежда, че for 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 (което е начинът, по който Explorer сортира), тъй като командният ред няма да сортира правилно числата, ако числото ‹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 shell, след което:

за i в {1..N} ; направете 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, който записва резултата в указания файл.


Ето алтернативен подход с помощта на 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 използва за сортиране на имена на файлове).

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