Перейти к содержимому

Как склеить код из разных файлов

  • автор:

Объединение содержимого из файлов разных форматов (LINQ) (C#)

В этом примере показано, как объединить данные из двух файлов с разделителями-запятыми, которые имеют общее значение, используемое в качестве совпадающего ключа. Этот способ может оказаться полезным, если необходимо объединить данные из двух электронных таблиц или из электронной таблицы и файла, имеющего другой формат, в новый файл. Можно изменить пример для обработки любого типа структурированного текста.

Создание файлов данных

  1. Скопируйте следующие строки в файл с именем scores.csv и сохраните его в папке проекта. Этот файл представляет данные электронной таблицы. Первый столбец представляет идентификатор учащегося, а столбцы со второго по пятый представляют результаты тестирования.
111, 97, 92, 81, 60 112, 75, 84, 91, 39 113, 88, 94, 65, 91 114, 97, 89, 85, 82 115, 35, 72, 91, 70 116, 99, 86, 90, 94 117, 93, 92, 80, 87 118, 92, 90, 83, 78 119, 68, 79, 88, 92 120, 99, 82, 81, 79 121, 96, 85, 91, 60 122, 94, 92, 91, 91 
Omelchenko,Svetlana,111 O'Donnell,Claire,112 Mortensen,Sven,113 Garcia,Cesar,114 Garcia,Debra,115 Fakhouri,Fadi,116 Feng,Hanying,117 Garcia,Hugo,118 Tucker,Lance,119 Adams,Terry,120 Zabokritski,Eugene,121 Tucker,Michael,122 

Пример

using System; using System.Collections.Generic; using System.Linq; class JoinStrings < static void Main() < // Join content from dissimilar files that contain // related information. File names.csv contains the student // name plus an ID number. File scores.csv contains the ID // and a set of four test scores. The following query joins // the scores to the student names by using ID as a // matching key. string[] names = System.IO.File.ReadAllLines(@"../../../names.csv"); string[] scores = System.IO.File.ReadAllLines(@"../../../scores.csv"); // Name: Last[0], First[1], ID[2] // Omelchenko, Svetlana, 11 // Score: StudentID[0], Exam1[1] Exam2[2], Exam3[3], Exam4[4] // 111, 97, 92, 81, 60 // This query joins two dissimilar spreadsheets based on common ID value. // Multiple from clauses are used instead of a join clause // in order to store results of id.Split. IEnumerablescoreQuery1 = from name in names let nameFields = name.Split(',') from id in scores let scoreFields = id.Split(',') where Convert.ToInt32(nameFields[2]) == Convert.ToInt32(scoreFields[0]) select nameFields[0] + "," + scoreFields[1] + "," + scoreFields[2] + "," + scoreFields[3] + "," + scoreFields[4]; // Pass a query variable to a method and execute it // in the method. The query itself is unchanged. OutputQueryResults(scoreQuery1, "Merge two spreadsheets:"); // Keep console window open in debug mode. Console.WriteLine("Press any key to exit"); Console.ReadKey(); > static void OutputQueryResults(IEnumerable query, string message) < Console.WriteLine(System.Environment.NewLine + message); foreach (string item in query) < Console.WriteLine(item); >Console.WriteLine(" total names in list", query.Count()); > > /* Output: Merge two spreadsheets: Omelchenko, 97, 92, 81, 60 O'Donnell, 75, 84, 91, 39 Mortensen, 88, 94, 65, 91 Garcia, 97, 89, 85, 82 Garcia, 35, 72, 91, 70 Fakhouri, 99, 86, 90, 94 Feng, 93, 92, 80, 87 Garcia, 92, 90, 83, 78 Tucker, 68, 79, 88, 92 Adams, 99, 82, 81, 79 Zabokritski, 96, 85, 91, 60 Tucker, 94, 92, 91, 91 12 total names in list */ 

Совместная работа с нами на GitHub

Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.

Сортировка и слияние данных из разных файлов в один

У меня возникла задача реализовать алгоритм слияние файлов (совместно с сортировкой) в один большой файл. Задача усложняется тем, что каждый файл полностью помещается в памяти, но все сразу — нет. Я решил отсортировать каждый файл по отдельности и затем слить их в один большой, но вот как производить слияние, если все вместе они не помещаются в памяти. Файлы содержат только числа от min(int64_t) и до max(int64_t), разделенные пробелом, например такая последовательность файлов:

test1.txt, test2.txt, test3.txt, test4.txt, test5.txt, test6.txt 

должна быть слита в такой файл:

test.txt 

Какой можно было бы выбрать способ или алгоритм для реализации данной задачи на С++ (готовые ф-ии использовать не буду, хочется самому написать код)?

Отслеживать
задан 7 июн 2022 в 12:08
713 8 8 серебряных знаков 29 29 бронзовых знаков

Читаете по одному элементу из всех файлов, выбираете наименьший, записываете в новый файл и читаете очередной элемент из того файла, элемент из которого записан. И так, пока все файлы не закончатся.

7 июн 2022 в 12:14

@Harry я об этом думал уже, но медленно же будет из-за того, что постоянно на диск буду ходить, никак нельзя сделать быстрее?

7 июн 2022 в 13:18

Ну если очень хочется — берите сразу кусками побольше, но чтоб в память влазили. А можете просто буферы чтения увеличить.

7 июн 2022 в 15:36

Если вы беспокоитесь о производительности, почему работаете с текстовыми файлами? Двоичные файлы читаются/пишутся намного быстрее текстовых.

21 июн 2022 в 21:55

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Для ускорения поможет буфер чтения. Просто читаем несколько чисел и их заносим в двумерный массив. А алгоритм слияния стандартный :

  • Находим минимальное число из первых, что хранятся в буфере
  • Вычёркиваем этот один элемент из буфера

Вот как реализовал буфера :

// несколько чисел на каждый файл int64_t bufer [ filesN ] [ bufsize ] ; // индекс первого числа int buferindex [ filesN ] ; // количество чисел заполнено int bufersize [ filesN ] ; // флаг конец файла достигнут bool fileseof [ filesN ] ; 

Функции в реализации :

читаю первое число, что находится в буфере i-го файла и записываю в указанное место памяти, возвращаю true или false

bool buffirst ( int , int64_t * ) ; 

удаляю первый элемент из буфера i-го файла

void popfirst ( int ) ; 

нахожу минимальное число из доступных первых, записываю результат в место памяти, удаляю этот элемент из буфера, возвращаю true или возвращаю false

bool findmin ( int64_t * ) ; 

в главной функции просто нахожу минимальное число с помощью findmin , и записываю в файл

Тестировал в Си и плюсах такой код :

// gcc -std=c11 -Os main.c -o main // g++ -x c++ -std=c++11 -Os main.c -o mainpp # include # include # include # include # include # include char const * files [ ] = < "test1.txt" , "test2.txt" , "test3.txt" , "test4.txt" , "test5.txt" , "test6.txt" >; char const fileo [ ] = "test.txt" ; enum < filesN = sizeof ( files ) / sizeof ( files [ 0 ] ) >; FILE * fa [ filesN ] ; FILE * fo ; enum < bufsize = 12 >; int64_t bufer [ filesN ] [ bufsize ] ; int buferindex [ filesN ] ; int bufersize [ filesN ] ; bool fileseof [ filesN ] ; // читаю первое число, что находится в // буфере [filei] файла и записываю в * xp , возвращаю true // или возвращаю false bool buffirst ( int const filei , int64_t * const xp ) < int const ind = buferindex [ filei ] ; if ( ind < bufersize [ filei ] ) < * xp = bufer [ filei ] [ ind ] ; return true ; >if ( fileseof [ filei ] ) return false ; bufersize [ filei ] = 0 ; < int i = 0 ; do < if ( fscanf ( fa [ filei ] , "%ld" , & ( bufer [ filei ] [ i ] ) ) != 1 ) < fileseof [ filei ] = true ; break ; >// if scanf ++ ( bufersize [ filei ] ) ; ++ i ; > while ( i < bufsize ) ; >// i if ( bufersize [ filei ] == 0 ) return false ; * xp = bufer [ filei ] [ 0 ] ; buferindex [ filei ] = 0 ; return true ; > // удаляю первый элемент из буфера [ bestfile ] файла static inline void popfirst ( int const bestfile ) < ++ ( buferindex [ bestfile ] ) ; >// нахожу минимальное число из доступных первых, // записываю результат в место памяти, // удаляю этот элемент из буфера, возвращаю true // или возвращаю false bool findmin ( int64_t * const xp ) < int64_t min ; int bestfile ; bool found = false ; for ( int i = 0 ; i < filesN ; ++ i ) < int64_t x ; if ( buffirst ( i , & x ) ) < if ( found ) < if ( x < min ) < min = x ; bestfile = i ; >> else < min = x ; bestfile = i ; found = true ; >> // if buffirst > // for i if ( found ) < * xp = min ; popfirst ( bestfile ) ; >return found ; > // нахожу минимальное число с помощью findmin , и записываю в файл int main ( ) < for ( int i = 0 ; i < filesN ; ++ i ) < fa [ i ] = fopen ( files [ i ] , "r" ) ; if ( fa [ i ] == NULL ) < fprintf(stderr,"fopen ( `%s` ) : %s\n",files [ i ],strerror(errno)); exit ( 1 ) ; >> // for i fo = fopen ( fileo , "w" ) ; if ( fo == NULL ) < fprintf(stderr,"fopen ( `%s` ) : %s\n",fileo,strerror(errno)); exit ( 1 ) ; >do < int64_t x ; if ( findmin ( & x ) ) < if ( fprintf ( fo , "%ld " , x ) < 0 ) < fputs("fprintf ( fo , \"%ld \" , x )\n",stderr); exit ( 1 ) ; >> else break ; > while ( true ) ; if ( fclose ( fo ) ) < fprintf(stderr,"fclose ( `%s` ) : %s\n",fileo,strerror(errno)); exit ( 1 ) ; >for ( int i = 0 ; i < filesN ; ++ i ) < if ( fclose ( fa [ i ] ) ) < fprintf(stderr,"fclose ( `%s` ) : %s\n",files [ i ],strerror(errno)); exit ( 1 ) ; >> // for i > 

Отслеживать
ответ дан 21 июн 2022 в 18:15
17.2k 1 1 золотой знак 9 9 серебряных знаков 33 33 бронзовых знака

К сожалению, я не могу сейчас тестировать такие большие файлы. Но все же решил поделится своей идеей. Так как автор вопроса написал хочется самому написать код я не буду лишать его такой возможности, и по этой же причине прошу не минусовать мой код приведенный на JavaScript поскольку он служит псевдокодом к ответу. Т.е. в данном случае я приведу лишь свою логику, а автор вопроса если она ему понравится сможет доработать ее на плюсах или любом другом языке, который сочтет нужным. Лично мне мое решение нравится как и сам вопрос, хотя решение не идеально (иногда и только в плане размеров файлов) в остальном оно рабочее.

  • идея алгоритма родилась из того что командой cat в linux и type в windows можно объединить файлы превышающие объем оперативки (я проверял на linux )
  • для демонстрации вместо файлов я использую массивы таким образом алгоритм легко протестировать даже в браузере
  • алгоритм гарантирует что левый(первый) файл не содержит числа превышающего любое из чисел в правом(следующем) файле
  • минусом алгоритма является то что он не гарантирует размещение в памяти отдельного файла (но частично это настраивается, хотя решение не полное если файл с одинаковыми числами не влезет в память)
  • проходим по всем файлам и сортируем их по отдельности
  • после того как у нас появилсись минимумы и максимумы в отдельных файлах мы можем найти общий минимум и максимум, а так же запомнить максимальный размер файла
  • далее мы создаем какое-то количество файлов (больше чем есть — лучше) в которые будем раскидывать наши числа, куда кидать число мы решаем согласно его величине и количеству файлов, таким образом меньшие числа попадут в первый файл а самые большие в последний
  • после того как мы раскидали числа по файлам, файлы нужно снова отсортировать так как первоначальная сортировка была нарушена
  • после того как мы отсортировали файлы нам остается только склеить их в один большой.
Отсортированные файлы: [ 31, 42, 94, 99, 106 ] [ 6, 109, 133, 135, 141 ] [ 6, 50, 57, 118, 126 ] < min: 6, max: 141, maxSizeFile: 17 >Проверка превышения размера файла: Все хорошо Проверка сортировки: Все хорошо [ 6, 6, 31, 42, 50, 57, 94, 99, 106, 109, 118, 126, 133, 135, 141 ] Запуск теста на 10000 итераций < errors: < testOversize: 1, testEqual: 0 >> 

Как видно при 10000 итерациях произошла 1 ошибка превышения размера файла , это значит что один из файлов оказался больше самого большого первоначального файла но я не измерял на сколько, возможно совсем на чуть-чуть, все дело в данных если к примеру будет идти очень много одинаковых чисел то по алгоритму они должны попасть в 1 файл и соответственно тот разростется в размерах — это единственный видимый мной минус данного подхода, возможно есть и другие которые я не вижу на данный момент, пока не придумал как это обойти.

По большей части я не стремился дать конкретный ответ, это бы заняло куда больше времени чем я уже потратил, просто решил предложить одну из идей для реализации, возможно это подтолкнет автора вопроса к своему решению.

function test(log = console.log) < let errors = < testOversize : 0, testEqual: 0 >// массивы как файлы // генерируем для примера const a = Array.from(Array(5)).map(e => Math.floor(Math.random() * 150)) const b = Array.from(Array(5)).map(e => Math.floor(Math.random() * 150)) const c = Array.from(Array(5)).map(e => Math.floor(Math.random() * 150)) // сколько файлов создать, // лучше больше чем есть так как числа могут совпадать // а это значит что один файл может стать больше чем положено const COUNT_FILES = 100 // вместимость в процентах на один файл const FIT_FILE = (100 / COUNT_FILES) // функция сортировки чисел const numSort = (a, b) => < if (a === b) return 0; return Math.sign(a - b)>/////////////////////////////////////////////////////////////////////// // 1) отсортировать файлы по отдельнсоти const a1 = a.sort(numSort) const b1 = b.sort(numSort) const c1 = c.sort(numSort) log('Отсортированные файлы:\n', a1, b1, c1) /////////////////////////////////////////////////////////////////////// // 2) найти минимум, максимум чисел // и максимальный размер одного файла (для теста алгоритма) let max = -Infinity // начинаем с наименьшего let min = Infinity // начинаем с наибольшего let maxSizeFile = 0 // начинаем с 0 for (arr of [a1, b1, c1]) < if (min >arr[0]) min = arr[0] if (max < arr[arr.length -1]) max = arr[arr.length -1] sizeFile = arr.join(' ').length // получаем размер файла в байтах (для теста) if (maxSizeFile < sizeFile) maxSizeFile = sizeFile >log() /////////////////////////////////////////////////////////////////////// // 3) раскидать данные в новые файлы files = <> // массивы как файлы в объекте (только для демонстрации) // cоздаем нужное количество массивов (файлов) for (let n = 0; n < COUNT_FILES; n++)< // например files['file0'] = [] file0 инициализируем пустым массивом files[`file$`] = [] > // имена файлов, // порядок важен в первый файл меньшие числа // в последний большие filesKey = Object.keys(files) for (arr of [a1, b1, c1]) < for (n of arr)< k = ((n - min) * 100) / (max - min) // нахождение позиции f = Math.floor(k / (FIT_FILE + 1)) // индекс файла для числа files[filesKey[f]].push(n) // записть в файл по имени (индексу) >> /////////////////////////////////////////////////////////////////////// // 4) после заполнения файлов сортируем каждый из них for (fileKey of Object.keys(files)) < files[fileKey].sort(numSort) >// содержимое файлов // log(JSON.stringify(files)) // объединение файлов // можно выполнить консольной коммандой перенаправления // (ее можно вызвать из C++ кода) // cat file1 file2 > newfile - для linux // type file1 file2 > newfile - для windows result = Object.values(files).reduce((acc, e) => [. acc, . e], []) // 5) на данном этапе все выполнено, осталось сделать проверки sizes = Object.values(files).map(e => e.join(' ').length) const testOversize = sizes.some(e => e > maxSizeFile) if (testOversize) errors.testOversize = 1 log(testOversize ? 'Проверка превышения размера файла: Размер превышен' + sizes.some(e => e > maxSizeFile) : 'Проверка превышения размера файла: Все хорошо') testEqual = result.join(' ') === [. a, . b, . c].sort(numSort).join(' ') if (!testEqual) errors.testEqual = 1 log(testEqual ? 'Проверка сортировки: Все хорошо' : 'Проверка сортировки: Ошибка') //выводим результирующий массив (файл) log(result) return errors > test() const nope = () => <> const iter = 10000 console.log(`Запуск теста на $ итераций`) let errors = < testOversize : 0, testEqual: 0 >for(let i=0; i < iter; i++) < const = test(nope) errors.testEqual += testEqual errors.testOversize += testOversize > console.log()

Объединение нескольких типов файлов в один документ с помощью C#

Чтобы объединить данные, которые присутствуют в нескольких документах, а иногда и в документах разных типов файлов, возникает необходимость объединить все ваши документы или часть документов в один. В этой статье вы узнаете, как программно объединить несколько документов одного или разных типов файлов в один файл с помощью C#.

Объединение PDF-презентаций Word Excel в один PDF-файл на C#

Ниже перечислены темы, которые рассматриваются ниже:

  • API .NET — объединение нескольких типов документов
  • Объединить файлы PDF, Word, Excel в один PDF
  • Объединить выбранные страницы из нескольких файлов в один файл

.NET API для объединения нескольких типов документов#

Сегодня я буду использовать GroupDocs.Merger for .NET, чтобы объединить документы разных форматов файлов в один файл. .NET API позволяет объединять различные документы одного или разных форматов в один файл. Кроме того, он позволяет разделять документы, обрезать документы и менять местами, перемещать, удалять, поворачивать или упорядочивать страницы. Кроме того, он поддерживает установку или удаление паролей для управления безопасностью поддерживаемых форматов документов.

Некоторые типы документов, поддерживаемые API, включают в себя; текстовые документы, электронные таблицы, презентации, HTML, PDF, электронные книги, рисунки Visio, CSV и TSV.

Загрузите установщик DLL или MSI из раздела загрузок или установите API в свое приложение .NET через NuGet.

PM> Install-Package GroupDocs.Merger 

Объединение файлов PDF, Word, Excel в один PDF-файл на C##

Вы можете комбинировать документы PDF с документами Word, презентациями и электронными таблицами Excel, написав всего несколько строк кода. Ниже приведены шаги по объединению документов нескольких типов файлов в один файл.

  • Загрузите исходный документ с помощью класса Merge.
  • Продолжайте объединять другие документы, используя метод Join.
  • Сохраните объединенный документ как вывод, используя метод Сохранить.

В следующем исходном коде показано, как объединить документы PDF, Word и Excel в один файл PDF на C#.

// Объединение двух или более разных типов файлов в один с помощью C# using (Merger merger = new Merger("document.pdf"))

Таким же образом вы можете комбинировать файлы одного формата. Упомянутый ниже результат — это результат, полученный путем объединения документа Word, документа PDF. и электронную таблицу, использующую приведенный выше код C#.

Объединение разных типов файлов в один PDF C#

Объединение отдельных страниц из нескольких файлов PDF, Word, Excel в один PDF-файл на С##

Объединить выбранные страницы разных типов файлов в один PDF C#

Не всегда хочется объединять весь документ. Вы можете выбрать несколько страниц из одного документа и несколько других страниц из следующего документа и так далее. API предоставляет различные способы объединения выбранных страниц из нескольких типов файлов в один файл.

  • Загрузите исходный документ, используя класс Merge.
  • Установите параметры слияния, используя класс JoinOptions.
  • Объедините документ, используя метод Join.
  • Продолжайте объединять документы, устанавливая различные параметры соединения для каждого документа.
  • Сохраните объединенный документ методом Сохранить.

В следующем исходном коде показано, как объединить файл PDF с первой страницей документа Word и четными листами книги Excel в указанном диапазоне в один файл PDF с помощью C#.

// Объедините отдельные страницы двух или более разных типов файлов в один с помощью C#. using (Merger merger = new Merger("document.pdf")) < // Объединить первую страницу файла DOCX JoinOptions joinOptions = new JoinOptions(new int[] ); merger.Join("document.docx", joinOptions); // Объединить все четные страницы/листы электронной таблицы из предоставленного диапазона joinOptions = new JoinOptions(1,2, RangeMode.EvenPages); merger.Join("spreadsheet.xlsx", joinOptions); merger.Save("merge_document.pdf"); > 

Вывод#

Подводя итог, вы увидели, как объединить два или более документов разных типов файлов в один файл с помощью C# в приложении .NET. Кроме того, вы научились комбинировать только избранные страницы нескольких типов файлов.

Вы можете узнать больше о GroupDocs.Merger for .NET, используя документацию. Если у вас возникнут вопросы, сообщите нам об этом через наш форум.

Смотрите также#

  • Объединить документы одного формата в C#
  • Разделить или объединить документы в Java
  • GroupDocs.Merger Product Family
  • Merge Documents in CSharp
  • Merge Files in CSharp
  • Merge multiple file types in CSharp
  • merge two or more files

Зачем это нужно?

Копипаст вручную — это, может, и не самый плохой вариант для небольшого количества файлов.

Но представьте, что вам нужно объединить 100+ файлов… готовы ли вы сделать все вручную? Эта затея весьма утомительна и чревата ошибками.

Для файлов с одинаковой структурой таблицы (те же заголовки и количество столбцов) можно воспользоваться скриптом на Python.

Шаг 1: Импортируйте пакеты и задайте рабочую директорию

Измените “/mydir” на нужную вам директорию.

import os
import glob
import pandas as pd
os.chdir("/mydir")

Шаг 2: Воспользуйтесь glob для сопоставления с шаблоном ‘csv’

Сопоставьте шаблон (‘csv’) и сохраните список имен файлов в переменной ‘all_filenames’. Здесь можно почитать о сопоставлении регулярных выражений.

extension = 'csv'
all_filenames = [i for i in glob.glob('*.<>'.format(extension))]

Шаг 3: Объедините файлы в список и экспортируйте в CSV

Воспользуйтесь pandas для объединения файлов в список и экспорта в CSV. На выходе получится файл “combined_csv.csv”. Найти его можно в рабочей директории.

Для экспорта «неанглийских» языков добавляется encoding = ‘utf-8-sig’.

#combine all files in the list
combined_csv = pd.concat([pd.read_csv(f) for f in all_filenames ])
#export to csv
combined_csv.to_csv( "combined_csv.csv", index=False, encoding='utf-8-sig')

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *