WARC 文件来自 Common Crawl。一个样品:
WARC-Type: response
WARC-Date: 2018-12-09T20:26:32Z
WARC-Record-ID: <urn:uuid:5e578aa4-4ec1-4b48-a3ff-cc0a154660f8>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<meta http-equiv="Content
环境:我在 Windows 的 VS 2019 上使用 C++。我不喜欢使用特殊的库。我查看了将文件映射到内存中,但有人说当您只是按顺序解析文件时它并没有那么快。因为我在 Windows 中,所以我得到了一个很好的 GUI,但我也得到了所有 Unicode 的混乱。
解析的期望输出:我有一个输出文件,我想在其中保存大部分文本和一些标签。我将丢弃大部分输入。一些warc标签向解析器发出信号,它可以向前跳过500个字符。例如,除“WARC-Type: response”之外的任何“WARC-Type”都可以向前跳过已知数量。
我尝试过:将文件读入堆缓冲区,然后使用滑动窗口对缓冲区进行切片。根据窗口内容跳过/保存。能够捕获跨越缓冲区的标签。最终,我将使用 regex 和 string::find 之类的东西来匹配标签和文本。
最大的问题:Unicode。该文件是 UTF-8 格式,包含您可以想象的各种有趣的字符。我使用 MultiByteToWideChar。如果我只转换窗口,我不会使用太多内存,但会遇到文本排列问题。UTF-8 的 15 个字符不会产生 ANSI 的 15 个字符。根据我的 multibtyetowidechar 标志、大小等。我会跳过文本、解码错误等。如果我转换整个缓冲区然后切片到一个窗口中,我使用的内存是原来的两倍。没什么大不了的,但似乎效率低下。
BOOL pageActive = FALSE;
BOOL xml = FALSE;
#define MAXBUFFERSIZE 1024
#define MAXTAGSIZE 64
DWORD windowStart = 0; DWORD windowEnd = 15; DWORD windowSize = 15;
DWORD bufferSize = MAXBUFFERSIZE;
_int64 fileRemaining;
HANDLE hFile;
DWORD dwBytesRead = 0;
LARGE_INTEGER dwPosition;
TCHAR* buffer;
hFile = CreateFile(
inputFilePath, // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file | FILE_FLAG_OVERLAPPED
NULL); // no attr. template
if (hFile == INVALID_HANDLE_VALUE)
{
DisplayErrorBox((LPWSTR)L"CreateFile");
return 0;
}
LARGE_INTEGER size;
GetFileSizeEx(hFile, &size);
_int64 fileSize = (__int64)size.QuadPart;
if(fileSize > MAXBUFFERSIZE){buffer = new TCHAR[MAXBUFFERSIZE];}
else{buffer = new TCHAR[fileSize];}
fileRemaining = fileSize;
while (fileRemaining) // outer loop
{
if (bufferSize > fileRemaining)
bufferSize = fileRemaining;
if (FALSE == ReadFile(hFile, buffer, bufferSize -1, &dwBytesRead, NULL))
{
sendToReportWindow(L"file read failed\n");
CloseHandle(hFile);
return 0;
}
fileRemaining -= bufferSize;
while (windowEnd < bufferSize) //inner loop. while unused data remains in buffer
{
windowSize = windowEnd - windowStart;
wstring str;
for (int i = windowStart; i <= windowEnd; i++) {
str.append(&buffer[i]);
}
str[windowEnd] = '\0';
TCHAR converted[MAXTAGSIZE] = { 0 };
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, (LPCCH)str.c_str(), -1, converted, MAXTAGSIZE);
sendToReportWindow(L"windowStart:%d windowEnd:%d converted:%s\n", windowStart, windowEnd, converted);
// skip these sections and continue to build the window unless there are sufficient characters in the window to make it worth checking its content.
// to do: WARC page state (use regex and string::find)
// allow skipping ~500 chars in some cases
// to do: XML tags/text
// keep track of tags that span multiple buffers
windowStart = windowEnd;
windowEnd++;
} // inner loop
delete [] buffer;
} // outer loop