以下を使用して非常に強力なマシンで開くのに約7分かかる150MBの1枚のExcelファイルがあります。
# using python
import xlrd
wb = xlrd.open_workbook(file)
sh = wb.sheet_by_index(0)
Excelファイルをより速く開く方法はありますか?私は非常に風変わりな提案(hadoop、spark、c、Javaなど)でも受け入れています。理想的ではない場合、30秒以内にファイルを開く方法を探しています。また、上記の例ではpythonを使用していますが、pythonである必要はありません。
注:これはクライアントからのExcelファイルです。受け取る前に他の形式に変換することはできません。ファイルではありません
UPDATE:30秒以内に次の200MBのExcelファイルを開くコードの実例で回答すると、報奨金が与えられます: https ://drive.google.com/file/d/0B_CXvCTOo7_2VW9id2VXRWZrbzQ/view?usp = sharing 。このファイルには、文字列(col 1)、日付(col 9)、および番号(col 11)が必要です。
あなたのExcelがあなたの例のようなCSVファイルのようにシンプルになる場合( https://drive.google.com/file/d/0B_CXvCTOo7_2UVZxbnpRaEVnaFk/view?usp=sharing )、ファイルをZipファイルとして開き、すべてのxmlを直接読み取ることができます。
Intel i5 4460、12 GB RAM、SSD Samsung EVO PRO。
多くのメモリRAMがある場合:このコードには多くのRAMが必要ですが、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は必要ないため、メモリを節約します): HDD、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;
}
}
Office製品で動作するほとんどのプログラミング言語には中間層があり、これが通常ボトルネックとなる場所です。良い例は、PIA/InteropまたはOpen XML SDKの使用です。
下位レベルでデータを取得する1つの方法(中間層をバイパス)は、ドライバーを使用することです。
150MBの1シートExcelファイル。約7分かかります。
私ができる最善の方法は、135秒で130MBのファイルで、およそ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);
7x64、Intel i5、2.3ghz、8GB RAM、SSD250GBを獲得してください。
ハードウェアソリューションも推奨できる場合、標準のHDDを使用している場合はSSDで解決してみてください。
注:企業のファイアウォールの内側にいるため、Excelスプレッドシートの例をダウンロードできません。
PS。 MSDN-200 MBのデータを含むxlsxファイルをインポートする最速の方法 を参照してください。OleDBであるconsensusが最も高速です。
PS 2. pythonでこれを行う方法は次のとおりです。 http://code.activestate.com/recipes/440661-read-tabular-data-from-Excel-spreadsheets-the-fast/
.NETコアとOpen XML SDKを使用して、約30秒でファイルを読み取ることができました。
次の例は、一致するタイプのすべての行とセルを含むオブジェクトのリストを返します。日付、数値、テキストのセルをサポートしています。プロジェクトはこちらから入手できます。 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ドライブ、8GB RAM、およびIntel Core i7-4710 CPU @ 2.50GHz(2コア)、Windows 10 64ビット)を搭載した3歳のラップトップでプログラムを実行しました。
ファイル全体を文字列として開いて解析するのにかかる時間は30秒未満ですが、最後の編集の例のようにオブジェクトを使用すると、ラップトップのラップトップでは時間が50秒近くになります。 Linuxを使用しているサーバーでは、おそらく30秒近くになります。
ここで説明したように、トリックはSAXアプローチを使用することでした。
https://msdn.Microsoft.com/en-us/library/office/gg575571.aspx
PythonのPandasライブラリを使用してデータを保持および処理できますが、それを使用して_.xlsx
_ファイルを直接ロードすると、非常に遅くなります。たとえば、 read_Excel()
。
1つのアプローチは、Pythonを使用して、Excel自体を使用してファイルのCSVへの変換を自動化し、次に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
_:ブール値、デフォルトはFalseTrueおよびparse_datesが有効になっている場合、pandasは列内の日時文字列の形式を推測しようとし、推測できる場合は、より高速な解析方法に切り替えます。場合によってはこれにより、解析速度が5〜10倍になります。
日付の形式が_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ドライブ
RAMドライブを使用して一時CSVファイルを保存すると、ロード時間がさらに短縮されます。
注:これは、Excelが利用可能なWindows PCを使用していることを前提としています。
サンプルJavaプログラムを作成しました。このプログラムは、ラップトップ(Intel i7 4コア、16 GB RAM)で最大40秒でファイルをロードできます。
https://github.com/skadyan/largefile
このプログラムは Apache POIライブラリー を使用して XSSF SAX API を使用して.xlsxファイルをロードします。
コールバックインターフェイスcom.stackoverlfow.largefile.RecordHandler
実装を使用して、Excelからロードされたデータを処理できます。このインターフェイスは、3つの引数を取るメソッドを1つだけ定義します
data map
:マップ:Excelセル参照およびExcel形式のセル値クラス com.stackoverlfow.largefile.Main
は、コンソールに行番号を出力するだけの、このインターフェースの1つの基本的な実装を示しています。
更新
woodstox パーサーは、標準のSAXReader
よりもパフォーマンスが優れているようです。 (コードはリポジトリで更新されました)。
また、目的のパフォーマンス要件を満たすために、org.Apache.poi...XSSFSheetXMLHandler
。実装では、より最適化された文字列/テキスト値の処理を実装でき、不必要なテキストフォーマット操作をスキップできます。
私はDell Precision T1700ワークステーションを使用しており、C#を使用して、標準コードを使用してファイルを開いてその内容を約24秒で読み取れ、相互運用サービスを使用してワークブックを開きました。ここにMicrosoft Excel 15.0 Object Libraryへの参照を使用したコードがあります。
私のusingステートメント:
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();
}
}
C#とOLEソリューションにはまだボトルネックがありますので、C++と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およびHDDマシンでは、xlsのセル数が50万の場合、1.5秒かかりますが、xlsxの同じデータには2.829秒かかります。したがって、30秒未満でデータを操作することは可能です。
本当に30秒未満が必要な場合は、RAM Driveを使用してファイルIOを削減します。プロセスを大幅に改善します。テストするデータをダウンロードできません。結果を教えてください。
Pythonではまったく達成できないようです。シートデータファイルを解凍すると、Cベースの反復SAXパーサーを通過するのに必要なすべての30秒かかります(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秒かかります。
ロード/操作時間を大幅に改善する別の方法はRAMDriveです
ファイルに十分なスペースと10%.. 20%の追加スペースを備えたRAMDriveを作成します...
RAMDriveのファイルをコピー...
そこからファイルをロードします...ドライブとファイルシステムに応じて、速度の改善は非常に大きくなります...
私のお気に入りはIMDiskツールキットです
( https://sourceforge.net/projects/imdisk-toolkit/ )ここには、すべてをスクリプト化する強力なコマンドラインがあります...
SoftPerfect ramdiskもお勧めします
( http://www.majorgeeks.com/files/details/softperfect_ram_disk.html )
しかし、それはあなたのOSにも依存します...
あなたがファイルを開いているシステムについてもっと情報が欲しい...とにかく:
と呼ばれるWindowsの更新をシステムで探します
「Office用Officeファイル検証アドイン...」
持っている場合は...アンインストールしてください...
ファイルははるかに速くロードされるはずです
特に共有からロードされる場合