Подтвердить что ты не робот

Как эффективно открыть огромный файл excel

У меня есть 150MB одностраничный файл excel, который занимает около 7 минут, чтобы открыть его на очень мощной машине, используя следующее:

# using python
import xlrd
wb = xlrd.open_workbook(file)
sh = wb.sheet_by_index(0)

Есть ли способ быстрее открыть файл Excel? Я открыт даже очень диковинным предложениям (например, hadoop, spark, c, java и т.д.). В идеале я ищу способ открыть файл менее чем за 30 секунд, если это не сон. Кроме того, в приведенном выше примере используется python, но он не должен быть python.


Примечание: это файл Excel от клиента. Он не может быть преобразован в какой-либо другой формат, прежде чем мы его получим. Это не наш файл


ОБНОВЛЕНИЕ:. Отвечайте на рабочий пример кода, который откроет следующий файл Excel объемом более 200 МБ менее чем за 30 секунд, будет вознагражден наградой: https://drive.google.com/file/d/0B_CXvCTOo7_2VW9id2VXRWZrbzQ/view?usp=sharing. Этот файл должен иметь строку (col 1), дату (col 9) и номер (col 11).

4b9b3361

Ответ 1

Хорошо, если ваш excel будет таким же простым, как файл CSV, например, ваш пример (https://drive.google.com/file/d/0B_CXvCTOo7_2UVZxbnpRaEVnaFk/view?usp=sharing), вы можете попробовать открыть файл в виде zip файла и прочитать сразу каждый xml:

Intel i5 4460, 12 ГБ оперативной памяти, SSD Samsung EVO PRO.

Если у вас много памяти: Для этого кода требуется много баранов, но требуется 20 ~ 25 секунд. (Вам нужен параметр -Xmx7g)

package com.devsaki.opensimpleexcel;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.zip.ZipFile;

public class Multithread {

    public static final char CHAR_END = (char) -1;

    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
        String excelFile = "C:/Downloads/BigSpreadsheetAllTypes.xlsx";
        ZipFile zipFile = new ZipFile(excelFile);
        long init = System.currentTimeMillis();
        ExecutorService executor = Executors.newFixedThreadPool(4);
        char[] sheet1 = readEntry(zipFile, "xl/worksheets/sheet1.xml").toCharArray();
        Future<Object[][]> futureSheet1 = executor.submit(() -> processSheet1(new CharReader(sheet1), executor));
        char[] sharedString = readEntry(zipFile, "xl/sharedStrings.xml").toCharArray();
        Future<String[]> futureWords = executor.submit(() -> processSharedStrings(new CharReader(sharedString)));

        Object[][] sheet = futureSheet1.get();
        String[] words = futureWords.get();

        executor.shutdown();

        long end = System.currentTimeMillis();
        System.out.println("only read: " + (end - init) / 1000);

        ///Doing somethin with the file::Saving as csv
        init = System.currentTimeMillis();
        try (PrintWriter writer = new PrintWriter(excelFile + ".csv", "UTF-8");) {
            for (Object[] rows : sheet) {
                for (Object cell : rows) {
                    if (cell != null) {
                        if (cell instanceof Integer) {
                            writer.append(words[(Integer) cell]);
                        } else if (cell instanceof String) {
                            writer.append(toDate(Double.parseDouble(cell.toString())));
                        } else {
                            writer.append(cell.toString()); //Probably a number
                        }
                    }
                    writer.append(";");
                }
                writer.append("\n");
            }
        }
        end = System.currentTimeMillis();
        System.out.println("Main saving to csv: " + (end - init) / 1000);
    }

    private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
    private static final LocalDateTime INIT_DATE = LocalDateTime.parse("1900-01-01T00:00:00+00:00", formatter).plusDays(-2);

    //The number in excel is from 1900-jan-1, so every number time that you get, you have to sum to that date
    public static String toDate(double s) {
        return formatter.format(INIT_DATE.plusSeconds((long) ((s*24*3600))));
    }

    public static String readEntry(ZipFile zipFile, String entry) throws IOException {
        System.out.println("Initialing readEntry " + entry);
        long init = System.currentTimeMillis();
        String result = null;

        try (BufferedReader br = new BufferedReader(new InputStreamReader(zipFile.getInputStream(zipFile.getEntry(entry)), Charset.forName("UTF-8")))) {
            br.readLine();
            result = br.readLine();
        }

        long end = System.currentTimeMillis();
        System.out.println("readEntry '" + entry + "': " + (end - init) / 1000);
        return result;
    }


    public static String[] processSharedStrings(CharReader br) throws IOException {
        System.out.println("Initialing processSharedStrings");
        long init = System.currentTimeMillis();
        String[] words = null;
        char[] wordCount = "Count=\"".toCharArray();
        char[] token = "<t>".toCharArray();
        String uniqueCount = extractNextValue(br, wordCount, '"');
        words = new String[Integer.parseInt(uniqueCount)];
        String nextWord;
        int currentIndex = 0;
        while ((nextWord = extractNextValue(br, token, '<')) != null) {
            words[currentIndex++] = nextWord;
            br.skip(11); //you can skip at least 11 chars "/t></si><si>"
        }
        long end = System.currentTimeMillis();
        System.out.println("SharedStrings: " + (end - init) / 1000);
        return words;
    }


    public static Object[][] processSheet1(CharReader br, ExecutorService executorService) throws IOException, ExecutionException, InterruptedException {
        System.out.println("Initialing processSheet1");
        long init = System.currentTimeMillis();
        char[] dimensionToken = "dimension ref=\"".toCharArray();
        String dimension = extractNextValue(br, dimensionToken, '"');
        int[] sizes = extractSizeFromDimention(dimension.split(":")[1]);
        br.skip(30); //Between dimension and next tag c exists more or less 30 chars
        Object[][] result = new Object[sizes[0]][sizes[1]];

        int parallelProcess = 8;
        int currentIndex = br.currentIndex;
        CharReader[] charReaders = new CharReader[parallelProcess];
        int totalChars = Math.round(br.chars.length / parallelProcess);
        for (int i = 0; i < parallelProcess; i++) {
            int endIndex = currentIndex + totalChars;
            charReaders[i] = new CharReader(br.chars, currentIndex, endIndex, i);
            currentIndex = endIndex;
        }
        Future[] futures = new Future[parallelProcess];
        for (int i = charReaders.length - 1; i >= 0; i--) {
            final int j = i;
            futures[i] = executorService.submit(() -> inParallelProcess(charReaders[j], j == 0 ? null : charReaders[j - 1], result));
        }
        for (Future future : futures) {
            future.get();
        }

        long end = System.currentTimeMillis();
        System.out.println("Sheet1: " + (end - init) / 1000);
        return result;
    }

    public static void inParallelProcess(CharReader br, CharReader back, Object[][] result) {
        System.out.println("Initialing inParallelProcess : " + br.identifier);

        char[] tokenOpenC = "<c r=\"".toCharArray();
        char[] tokenOpenV = "<v>".toCharArray();

        char[] tokenAttributS = " s=\"".toCharArray();
        char[] tokenAttributT = " t=\"".toCharArray();

        String v;
        int firstCurrentIndex = br.currentIndex;
        boolean first = true;

        while ((v = extractNextValue(br, tokenOpenC, '"')) != null) {
            if (first && back != null) {
                int sum = br.currentIndex - firstCurrentIndex - tokenOpenC.length - v.length() - 1;
                first = false;
                System.out.println("Adding to : " + back.identifier + " From : " + br.identifier);
                back.plusLength(sum);
            }
            int[] indexes = extractSizeFromDimention(v);

            int s = foundNextTokens(br, '>', tokenAttributS, tokenAttributT);
            char type = 's'; //3 types: number (n), string (s) and date (d)
            if (s == 0) { // Token S = number or date
                char read = br.read();
                if (read == '1') {
                    type = 'n';
                } else {
                    type = 'd';
                }
            } else if (s == -1) {
                type = 'n';
            }
            String c = extractNextValue(br, tokenOpenV, '<');
            Object value = null;
            switch (type) {
                case 'n':
                    value = Double.parseDouble(c);
                    break;
                case 's':
                    try {
                        value = Integer.parseInt(c);
                    } catch (Exception ex) {
                        System.out.println("Identifier Error : " + br.identifier);
                    }
                    break;
                case 'd':
                    value = c.toString();
                    break;
            }
            result[indexes[0] - 1][indexes[1] - 1] = value;
            br.skip(7); ///v></c>
        }
    }

    static class CharReader {
        char[] chars;
        int currentIndex;
        int length;

        int identifier;

        public CharReader(char[] chars) {
            this.chars = chars;
            this.length = chars.length;
        }

        public CharReader(char[] chars, int currentIndex, int length, int identifier) {
            this.chars = chars;
            this.currentIndex = currentIndex;
            if (length > chars.length) {
                this.length = chars.length;
            } else {
                this.length = length;
            }
            this.identifier = identifier;
        }

        public void plusLength(int n) {
            if (this.length + n <= chars.length) {
                this.length += n;
            }
        }

        public char read() {
            if (currentIndex >= length) {
                return CHAR_END;
            }
            return chars[currentIndex++];
        }

        public void skip(int n) {
            currentIndex += n;
        }
    }


    public static int[] extractSizeFromDimention(String dimention) {
        StringBuilder sb = new StringBuilder();
        int columns = 0;
        int rows = 0;
        for (char c : dimention.toCharArray()) {
            if (columns == 0) {
                if (Character.isDigit(c)) {
                    columns = convertExcelIndex(sb.toString());
                    sb = new StringBuilder();
                }
            }
            sb.append(c);
        }
        rows = Integer.parseInt(sb.toString());
        return new int[]{rows, columns};
    }

    public static int foundNextTokens(CharReader br, char until, char[]... tokens) {
        char character;
        int[] indexes = new int[tokens.length];
        while ((character = br.read()) != CHAR_END) {
            if (character == until) {
                break;
            }
            for (int i = 0; i < indexes.length; i++) {
                if (tokens[i][indexes[i]] == character) {
                    indexes[i]++;
                    if (indexes[i] == tokens[i].length) {
                        return i;
                    }
                } else {
                    indexes[i] = 0;
                }
            }
        }

        return -1;
    }

    public static String extractNextValue(CharReader br, char[] token, char until) {
        char character;
        StringBuilder sb = new StringBuilder();
        int index = 0;

        while ((character = br.read()) != CHAR_END) {
            if (index == token.length) {
                if (character == until) {
                    return sb.toString();
                } else {
                    sb.append(character);
                }
            } else {
                if (token[index] == character) {
                    index++;
                } else {
                    index = 0;
                }
            }
        }
        return null;
    }

    public static int convertExcelIndex(String index) {
        int result = 0;
        for (char c : index.toCharArray()) {
            result = result * 26 + ((int) c - (int) 'A' + 1);
        }
        return result;
    }
}

Старый ответ (не нужен параметр Xms7g, поэтому меньше памяти): Для открытия и чтения файла примера около 35 секунд (200 МБ) с жесткого диска, SDD занимает немного меньше (30 секунд).

Здесь код: https://github.com/csaki/OpenSimpleExcelFast.git

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.zip.ZipFile;

public class Launcher {

    public static final char CHAR_END = (char) -1;

    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
        long init = System.currentTimeMillis();
        String excelFile = "D:/Downloads/BigSpreadsheet.xlsx";
        ZipFile zipFile = new ZipFile(excelFile);

        ExecutorService executor = Executors.newFixedThreadPool(4);
        Future<String[]> futureWords = executor.submit(() -> processSharedStrings(zipFile));
        Future<Object[][]> futureSheet1 = executor.submit(() -> processSheet1(zipFile));
        String[] words = futureWords.get();
        Object[][] sheet1 = futureSheet1.get();
        executor.shutdown();

        long end = System.currentTimeMillis();
        System.out.println("Main only open and read: " + (end - init) / 1000);


        ///Doing somethin with the file::Saving as csv
        init = System.currentTimeMillis();
        try (PrintWriter writer = new PrintWriter(excelFile + ".csv", "UTF-8");) {
            for (Object[] rows : sheet1) {
                for (Object cell : rows) {
                    if (cell != null) {
                        if (cell instanceof Integer) {
                            writer.append(words[(Integer) cell]);
                        } else if (cell instanceof String) {
                            writer.append(toDate(Double.parseDouble(cell.toString())));
                        } else {
                            writer.append(cell.toString()); //Probably a number
                        }
                    }
                    writer.append(";");
                }
                writer.append("\n");
            }
        }
        end = System.currentTimeMillis();
        System.out.println("Main saving to csv: " + (end - init) / 1000);
    }

    private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
    private static final LocalDateTime INIT_DATE = LocalDateTime.parse("1900-01-01T00:00:00+00:00", formatter).plusDays(-2);

    //The number in excel is from 1900-jan-1, so every number time that you get, you have to sum to that date
    public static String toDate(double s) {
        return formatter.format(INIT_DATE.plusSeconds((long) ((s*24*3600))));
    }

    public static Object[][] processSheet1(ZipFile zipFile) throws IOException {
        String entry = "xl/worksheets/sheet1.xml";
        Object[][] result = null;
        char[] dimensionToken = "dimension ref=\"".toCharArray();
        char[] tokenOpenC = "<c r=\"".toCharArray();
        char[] tokenOpenV = "<v>".toCharArray();

        char[] tokenAttributS = " s=\"".toCharArray();
        char[] tokenAttributT = " t=\"".toCharArray();
        try (BufferedReader br = new BufferedReader(new InputStreamReader(zipFile.getInputStream(zipFile.getEntry(entry)), Charset.forName("UTF-8")))) {
            String dimension = extractNextValue(br, dimensionToken, '"');
            int[] sizes = extractSizeFromDimention(dimension.split(":")[1]);
            br.skip(30); //Between dimension and next tag c exists more or less 30 chars
            result = new Object[sizes[0]][sizes[1]];
            String v;
            while ((v = extractNextValue(br, tokenOpenC, '"')) != null) {
                int[] indexes = extractSizeFromDimention(v);

                int s = foundNextTokens(br, '>', tokenAttributS, tokenAttributT);
                char type = 's'; //3 types: number (n), string (s) and date (d)
                if (s == 0) { // Token S = number or date
                    char read = (char) br.read();
                    if (read == '1') {
                        type = 'n';
                    } else {
                        type = 'd';
                    }
                } else if (s == -1) {
                    type = 'n';
                }
                String c = extractNextValue(br, tokenOpenV, '<');
                Object value = null;
                switch (type) {
                    case 'n':
                        value = Double.parseDouble(c);
                        break;
                    case 's':
                        value = Integer.parseInt(c);
                        break;
                    case 'd':
                        value = c.toString();
                        break;
                }
                result[indexes[0] - 1][indexes[1] - 1] = value;
                br.skip(7); ///v></c>
            }
        }
        return result;
    }

    public static int[] extractSizeFromDimention(String dimention) {
        StringBuilder sb = new StringBuilder();
        int columns = 0;
        int rows = 0;
        for (char c : dimention.toCharArray()) {
            if (columns == 0) {
                if (Character.isDigit(c)) {
                    columns = convertExcelIndex(sb.toString());
                    sb = new StringBuilder();
                }
            }
            sb.append(c);
        }
        rows = Integer.parseInt(sb.toString());
        return new int[]{rows, columns};
    }

    public static String[] processSharedStrings(ZipFile zipFile) throws IOException {
        String entry = "xl/sharedStrings.xml";
        String[] words = null;
        char[] wordCount = "Count=\"".toCharArray();
        char[] token = "<t>".toCharArray();
        try (BufferedReader br = new BufferedReader(new InputStreamReader(zipFile.getInputStream(zipFile.getEntry(entry)), Charset.forName("UTF-8")))) {
            String uniqueCount = extractNextValue(br, wordCount, '"');
            words = new String[Integer.parseInt(uniqueCount)];
            String nextWord;
            int currentIndex = 0;
            while ((nextWord = extractNextValue(br, token, '<')) != null) {
                words[currentIndex++] = nextWord;
                br.skip(11); //you can skip at least 11 chars "/t></si><si>"
            }
        }
        return words;
    }

    public static int foundNextTokens(BufferedReader br, char until, char[]... tokens) throws IOException {
        char character;
        int[] indexes = new int[tokens.length];
        while ((character = (char) br.read()) != CHAR_END) {
            if (character == until) {
                break;
            }
            for (int i = 0; i < indexes.length; i++) {
                if (tokens[i][indexes[i]] == character) {
                    indexes[i]++;
                    if (indexes[i] == tokens[i].length) {
                        return i;
                    }
                } else {
                    indexes[i] = 0;
                }
            }
        }

        return -1;
    }

    public static String extractNextValue(BufferedReader br, char[] token, char until) throws IOException {
        char character;
        StringBuilder sb = new StringBuilder();
        int index = 0;

        while ((character = (char) br.read()) != CHAR_END) {
            if (index == token.length) {
                if (character == until) {
                    return sb.toString();
                } else {
                    sb.append(character);
                }
            } else {
                if (token[index] == character) {
                    index++;
                } else {
                    index = 0;
                }
            }
        }
        return null;
    }

    public static int convertExcelIndex(String index) {
        int result = 0;
        for (char c : index.toCharArray()) {
            result = result * 26 + ((int) c - (int) 'A' + 1);
        }
        return result;
    }

}

Ответ 2

Большинство языков программирования, которые работают с продуктами Office, имеют некоторый средний уровень, и обычно это место является узким местом, хорошим примером является использование PIA/Interop или Open XML SDK.

Один из способов получения данных на более низком уровне (обход среднего уровня) - использование драйвера.

150MB одностраничный файл excel, который занимает около 7 минут.

Лучшее, что я могу сделать, это 130 МБ файл за 135 секунд, примерно в 3 раза быстрее:

Stopwatch sw = new Stopwatch();
sw.Start();

DataSet excelDataSet = new DataSet();

string filePath = @"c:\temp\BigBook.xlsx";

// For .XLSXs we use =Microsoft.ACE.OLEDB.12.0;, for .XLS we'd use Microsoft.Jet.OLEDB.4.0; with  "';Extended Properties=\"Excel 8.0;HDR=YES;\"";
string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + filePath + "';Extended Properties=\"Excel 12.0;HDR=YES;\"";

using (OleDbConnection conn = new OleDbConnection(connectionString))
{
    conn.Open();
    OleDbDataAdapter objDA = new System.Data.OleDb.OleDbDataAdapter
    ("select * from [Sheet1$]", conn);
    objDA.Fill(excelDataSet);
    //dataGridView1.DataSource = excelDataSet.Tables[0];
}
sw.Stop();
Debug.Print("Load XLSX tool: " + sw.ElapsedMilliseconds + " millisecs. Records = "  + excelDataSet.Tables[0].Rows.Count);

введите описание изображения здесь

Win 7x64, Intel i5, 2.3ghz, 8GB RAM, SSD250GB.

Если бы я мог порекомендовать аппаратное решение, попробуйте разрешить его с помощью SSD, если вы используете стандартные жесткие диски.

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

PS. См. MSDN - Самый быстрый способ импортировать файлы xlsx с 200 МБ данных, консенсус в том, что OleDB является самым быстрым.

PS 2. Здесь вы можете сделать это с помощью python:  http://code.activestate.com/recipes/440661-read-tabular-data-from-excel-spreadsheets-the-fast/

Ответ 3

Мне удалось прочитать файл примерно через 30 секунд с использованием ядра .NET и SDK Open XML.

Следующий пример возвращает список объектов, содержащих все строки и ячейки с соответствующими типами, поддерживает даты, числовые и текстовые ячейки. Проект доступен здесь: https://github.com/xferaa/BigSpreadSheetExample/ (должен работать в Windows, Linux и Mac OS и не требует, чтобы Excel или любой компонент Excel были установлен).

public List<List<object>> ParseSpreadSheet()
{
    List<List<object>> rows = new List<List<object>>();

    using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(filePath, false))
    {
        WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
        WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();

        OpenXmlReader reader = OpenXmlReader.Create(worksheetPart);

        Dictionary<int, string> sharedStringCache = new Dictionary<int, string>();

        int i = 0;
        foreach (var el in workbookPart.SharedStringTablePart.SharedStringTable.ChildElements)
        {
            sharedStringCache.Add(i++, el.InnerText);
        }

        while (reader.Read())
        {
            if(reader.ElementType == typeof(Row))
            {
                reader.ReadFirstChild();

                List<object> cells = new List<object>();

                do
                {
                    if (reader.ElementType == typeof(Cell))
                    {
                        Cell c = (Cell)reader.LoadCurrentElement();

                        if (c == null || c.DataType == null || !c.DataType.HasValue)
                            continue;

                        object value;

                        switch(c.DataType.Value)
                        {
                            case CellValues.Boolean:
                                value = bool.Parse(c.CellValue.InnerText);
                                break;
                            case CellValues.Date:
                                value = DateTime.Parse(c.CellValue.InnerText);
                                break;
                            case CellValues.Number:
                                value = double.Parse(c.CellValue.InnerText);
                                break;
                            case CellValues.InlineString:
                            case CellValues.String:
                                value = c.CellValue.InnerText;
                                break;
                            case CellValues.SharedString:
                                value = sharedStringCache[int.Parse(c.CellValue.InnerText)];
                                break;
                            default:
                                continue;
                        }

                        if (value != null)
                            cells.Add(value);
                    }

                } while (reader.ReadNextSibling());

                if (cells.Any())
                    rows.Add(cells);
            }
        }
    }

    return rows;
}

Я запустил программу на трехлетнем ноутбуке с SSD-накопителем, 8 ГБ оперативной памяти и процессором Intel Core i7-4710 с частотой 2.50 ГГц (два ядра) на 64-разрядной версии Windows.

Обратите внимание, что хотя открытие и разбор всего файла в виде строк занимает чуть меньше 30 секунд, при использовании объектов, как в примере моего последнего редактирования, время доходит до почти 50 секунд с моим дрянным ноутбуком. Вероятно, вы будете ближе к 30 секундам на своем сервере с Linux.

Трюк состоял в том, чтобы использовать SAX-подход, как описано здесь:

https://msdn.microsoft.com/en-us/library/office/gg575571.aspx

Ответ 4

Библиотека Python Pandas может использоваться для хранения и обработки ваших данных, но использование ее для прямой загрузки файла .xlsx будет довольно медленным, например. используя read_excel().

Один из подходов заключается в использовании Python для автоматизации преобразования вашего файла в CSV с использованием самой Excel и последующего использования Pandas для загрузки результирующего файла CSV с помощью read_csv(). Это даст вам хорошую скорость, но не менее 30 секунд:

import win32com.client as win32        
import pandas as pd    
from datetime import datetime    

print ("Starting")
start = datetime.now()

# Use Excel to load the xlsx file and save it in csv format
excel = win32.gencache.EnsureDispatch('Excel.Application')
wb = excel.Workbooks.Open(r'c:\full path\BigSpreadsheet.xlsx')
excel.DisplayAlerts = False
wb.DoNotPromptForConvert = True
wb.CheckCompatibility = False

print('Saving')
wb.SaveAs(r'c:\full path\temp.csv', FileFormat=6, ConflictResolution=2) 
excel.Application.Quit()

# Use Pandas to load the resulting CSV file
print('Loading CSV')
df = pd.read_csv(r'c:\full path\temp.csv', dtype=str)

print(df.shape)
print("Done", datetime.now() - start)

Типы столбцов
Типы для ваших столбцов можно указать, передав dtype и converters и parse_dates:

df = pd.read_csv(r'c:\full path\temp.csv', dtype=str, converters={10:int}, parse_dates=[8], infer_datetime_format=True)

Вы также должны указать infer_datetime_format=True, поскольку это значительно ускорит преобразование даты.

nfer_datetime_format: boolean, по умолчанию False

Если True и parse_dates включены, Pandas будет пытаться вывести формат строк datetime в столбцах, и если это может быть inferred, переключитесь на более быстрый метод их разбора. В некоторых случаях это может увеличить скорость разбора на 5-10x.

Также добавьте dayfirst=True, если даты указаны в форме DD/MM/YYYY.

Селективные столбцы
Если вам действительно нужно работать только с столбцами 1 9 11, вы можете дополнительно сократить ресурсы, указав usecols=[0, 8, 10] следующим образом:

df = pd.read_csv(r'c:\full path\temp.csv', dtype=str, converters={10:int}, parse_dates=[1], dayfirst=True, infer_datetime_format=True, usecols=[0, 8, 10])

Полученный в результате фреймворк будет содержать только эти 3 столбца данных.

ОЗУ
Использование RAM-диска для хранения временного файла CSV для дальнейшего ускорения времени загрузки.

Примечание. Это предполагает, что вы используете доступ к ПК с Windows.

Ответ 5

Я использую рабочую станцию ​​Dell Precision T1700 и используя С#, я смог открыть файл и прочитать его содержимое примерно за 24 секунды, просто используя стандартный код, чтобы открыть книгу с помощью межсетевых сервисов. Использование ссылок на библиотеку объектов Microsoft Excel 15.0 здесь - мой код.

Мои операторы:

using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;

Код для открытия и чтения книги:

public partial class MainWindow : Window {
    public MainWindow() {
        InitializeComponent();

        Excel.Application xlApp;
        Excel.Workbook wb;
        Excel.Worksheet ws;

        xlApp = new Excel.Application();
        xlApp.Visible = false;
        xlApp.ScreenUpdating = false;

        wb = xlApp.Workbooks.Open(@"Desired Path of workbook\Copy of BigSpreadsheet.xlsx");

        ws = wb.Sheets["Sheet1"];

        //string rng = ws.get_Range("A1").Value;
        MessageBox.Show(ws.get_Range("A1").Value);

        Marshal.FinalReleaseComObject(ws);

        wb.Close();
        Marshal.FinalReleaseComObject(wb);

        xlApp.Quit();
        Marshal.FinalReleaseComObject(xlApp);

        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

Ответ 6

Я создал образец Java, который может загрузить файл за 40 секунд моего ноутбука (Intel i7 4 ядра, 16 ГБ оперативной памяти).

https://github.com/skadyan/largefile

Эта программа использует Apache POI library для загрузки файла .xlsx с помощью XSSF SAX API.

Реализация интерфейса обратного вызова com.stackoverlfow.largefile.RecordHandler может использоваться для обработки данных, загруженных из Excel. Этот интерфейс определяет только один метод, который принимает три аргумента

  • имя листа: String, имя листа excel
  • номер строки: int, номер строки данных
  • и data map: Карта: ссылка на ячейку excel и форматированное значение ячейки excel

Класс com.stackoverlfow.largefile.Main демонстрирует одну базовую реализацию этого интерфейса, которая просто печатает номер строки на консоли.

Обновление

woodstox Парсер, похоже, имеет лучшую производительность, чем стандартный SAXReader. (код обновлен в репо).

Кроме того, чтобы удовлетворить требуемые требования к производительности, вы можете подумать о повторной реализации org.apache.poi...XSSFSheetXMLHandler. В реализации может быть реализована более оптимизированная обработка строковых/текстовых значений и может быть пропущена ненужная операция форматирования текста.

Ответ 7

Похоже, что это почти невозможно в Python. Если мы распакуем файл данных листа, потребуется всего 30 секунд, чтобы передать его через синтаксический анализатор SAX на основе C (используя lxml, очень быструю обертку поверх libxml2):

from __future__ import print_function

from lxml import etree
import time


start_ts = time.time()

for data in etree.iterparse(open('xl/worksheets/sheet1.xml'), events=('start',), 
                            collect_ids=False, resolve_entities=False,
                            huge_tree=True):
    pass

print(time.time() - start_ts)

Выход образца: 27.2134890556

Кстати, самому Excel требуется около 40 секунд для загрузки книги.

Ответ 8

У С# и ole-решения все еще есть узкое место. Поэтому я проверяю его на С++ и ado.

_bstr_t connStr(makeConnStr(excelFile, header).c_str());

TESTHR(pRec.CreateInstance(__uuidof(Recordset)));       
TESTHR(pRec->Open(sqlSelectSheet(connStr, sheetIndex).c_str(), connStr, adOpenStatic, adLockOptimistic, adCmdText));

while(!pRec->adoEOF)
{
    for(long i = 0; i < pRec->Fields->GetCount(); ++i)
    {   
        _variant_t v = pRec->Fields->GetItem(i)->Value;
        if(v.vt == VT_R8)
            num[i] = v.dblVal;
        if(v.vt == VT_BSTR)
            str[i] = v.bstrVal;          
        ++cellCount;
    }                                    
    pRec->MoveNext();
}

В i5-4460 и на жестком диске я нахожу 500 тысяч ячеек в xls, будет занимать 1.5. Но те же данные в xlsx будут принимать 2,829. Также возможно управлять вашими данными в возрасте до 30 лет.

Если вам действительно нужно менее 30 секунд, используйте RAM Drive для уменьшения IO файла. Это значительно улучшит ваш процесс. Я не могу загрузить ваши данные, чтобы проверить его, поэтому, пожалуйста, скажите мне результат.

Ответ 9

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

создать RAMDrive с достаточным пространством для вашего файла и 10%.. 20% дополнительного места...
скопируйте файл для RAMDrive...
Загрузите файл оттуда... в зависимости от вашего диска и файловой системы улучшение скорости должно быть огромным...

Мой любимый инструментарий IMDisk
(https://sourceforge.net/projects/imdisk-toolkit/) здесь у вас есть мощная командная строка для script всего...

Я также рекомендую ramdisk SoftPerfect
(http://www.majorgeeks.com/files/details/softperfect_ram_disk.html)

но это также зависит от вашей ОС...

Ответ 10

Я хотел бы получить дополнительную информацию о системе, в которой вы открывают файл... в любом случае:

загляните в свою систему для обновления Windows под названием
"Надстройка для проверки файлов Office для Office..."

если у вас есть... удалить его...
файл должен загружаться намного быстрее
особенно если он загружен из общего ресурса

Ответ 11

Вы пробовали загружать рабочий лист по запросу, доступный с версии 0.7.1 из xlrd?

Для этого вам необходимо передать on_demand=True в open_workbook().

xlrd.open_workbook (filename = None, logfile = < _io.TextIOWrapper name= '' mode = 'w' encoding = 'UTF-8' > , verbosity = 0, use_mmap = 1, file_contents = None, encoding_override = None, formatting_info = False, on_demand = False, ragged_rows = False)


Другие потенциальные решения python, которые я нашел для чтения файла xlsx:

  • Прочитайте raw xml в 'xl/sharedStrings.xml' и 'xl/worksheets/sheet1.xml'
  • Попробуйте openpyxl library Read Only mode, который также оптимизируется при использовании памяти для больших файлов.

    from openpyxl import load_workbook wb = load_workbook(filename='large_file.xlsx', read_only=True) ws = wb['big_data']
    
    for row in ws.rows:
        for cell in row:
            print(cell.value)
    
  • Если вы работаете в Windows, вы можете использовать PyWin32 и 'Excel.Application'

    import time
    import win32com.client as win32
    def excel():
       xl = win32.gencache.EnsureDispatch('Excel.Application')
       ss = xl.Workbooks.Add()
    ...
    

Ответ 12

Сохраните свой Excel файл в файле с разделителями табуляции и откройте его, как обычно, вы читаете обычный txt:)

edit: вы можете прочитать файл по строкам и разделить строки на вкладках. Получите столбцы данных, которые вам нужны по индексу.