【发布时间】:2021-03-03 12:36:42
【问题描述】:
处理通用爬取warc文件。这些是 5gb 未压缩。里面有text,xml和warc headers。
这是我特别遇到问题的代码:
wstring sub = buffer->substr(windowStart, windowSize);
这给了我错误,“表达式必须有一个指向类类型的指针”。我认为这是因为标签是指向该大小的堆内存位置的指针。因此,我无法对其运行任何字符串操作。但是 -> 操作符应该得到它指向的内容,这样我就可以运行类似 substr 的东西?
我正在使用这样的简单缓冲区,因为我知道将文件(MapViewOfFile 等)映射到内存更适合随机访问。如果我只需要顺序读取,它实际上会更慢吗?
我想按顺序读取文件。为了提高速度,将文件分块读取到 RAM 中,然后在从磁盘获取另一个块之前处理 ram 块。比如说每块 1mb,等等。
我没有处理所有的 xml,有些会被跳过。抓取文本和一些 warc 标头,跳过其余部分。
这个想法是通过 ram 中的文件块使用滑动窗口。窗口从块中上次停止的位置开始。窗口在循环中增大。一旦达到足够的大小,正则表达式将用于检查是否有任何匹配的标签、标题或文本。如果是这样,要么只跳过那个标签,要么跳过这么多字符(如果遇到特定类型的 warc 标头,在某些情况下会跳过 500 个字符),写那个标签(如果我想保留它的话)等等。
当窗口匹配时,windowStart 设置为等于 windowEnd 并开始再次扩展窗口以查找下一个模式。一旦缓冲区结束,它会跟踪任何部分标记并从磁盘重新填充缓冲区。
我遇到的主要问题是如何做滑动窗口。缓冲区是指向堆内存中某个位置的指针。由于某种原因,我不能在其上使用句点或 -> 运算符。所以我不能使用 substr、regex 等。我可以制作一个副本,但我真的需要这样做吗?
到目前为止,这是我的代码:
BOOL pageActive = FALSE;
BOOL xml = FALSE;
#define MAXBUFFERSIZE 1024
#define MAXTAGSIZE 64
DWORD windowStart = 0; DWORD windowEnd = 15; DWORD windowSize = 15; // buffer window containing tag candidate
wstring windowCopy;
DWORD bufferSize = MAXBUFFERSIZE;
_int64 fileRemaining;
HANDLE hFile;
DWORD dwBytesRead = 0;
OVERLAPPED ol = { 0 };
LARGE_INTEGER dwPosition;
TCHAR* buffer;
hFile = CreateFile(
inputFilePath, // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ | FILE_SHARE_WRITE, // share for reading and writing
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;
double gigabytes = fileSize * 9.3132e-10;
sendToReportWindow(L"file size: %lld bytes \(%.1f gigabytes\)\n", fileSize, gigabytes);
if(fileSize > MAXBUFFERSIZE)
{
TCHAR* buffer = new TCHAR[MAXBUFFERSIZE]; buffer[0] = 0;
//sendToReportWindow(L"buffer is MAXBUFFERSIZE\n");
}
else
{
TCHAR* buffer = new TCHAR[fileSize]; buffer[0] = 0;
//sendToReportWindow(L"buffer is fileSize + 1\n");
}
fileRemaining = fileSize;
sendToReportWindow(L"file remaining: %lld bytes\n", fileRemaining);
//TCHAR readBuffer[MAXBUFFERSIZE] = { 0 };
while (fileRemaining) // outer loop. while file remaining, read file chunk to buffer
{
if (bufferSize > fileRemaining) // as fileremaining gets smaller as file is processed, it eventually is smaller than the buffer
bufferSize = fileRemaining;
if (FALSE == ReadFile(hFile, buffer, bufferSize -1, &dwBytesRead, NULL))
//if (FALSE == ReadFile(hFile, readBuffer, bufferSize -1, &dwBytesRead, NULL))
{
sendToReportWindow(L"file read failed\n");
CloseHandle(hFile);
return 0;
}
fileRemaining -= bufferSize; //fileRemaining is size of the file left after this buffer is processed
sendToReportWindow(L"outer loop\n");
// declare and clear span char array[maxTagSize] // size of array is maximum tag size (64). This is for unused windows. Raw text is not considered a tag
while (windowEnd < bufferSize) //inner loop. while unused data remains in buffer
{
windowSize = windowEnd - windowStart;
// windowsize += span.size
// The window start position remains fixed as the window size is slowly increased. Once it is large enough, some conditional below begin to look at it.If any triggers, they eat that window. Setting the new start position at the previous end position.
// If the buffer ends mid - tag, the contents of the window are copy to the span array variable
// Page state. Tags in header
// If !pageActive
// if windowSize > 7 (warc / 1.0)
// Convert chunk to string for regex ? (prepend span array from previous loop)
// If Regex chunk WARC - Type : response pageActive = true; wstart = wend, clear span
// Elseif regex chunk other warc - type clear span; skip ahead 550 for start, 565 for end
// Continue
// // page is active
//
// if windowSize > 6
// If regex chunk WARC / \d pageActive = false; xml = false; wstart = wend, clear span; Continue
// If !xml
// If windowSize > 15 (warc date)
// Convert chunk to string for regex ? (prepend span array from previous loop)
// If regex chunk warc date output warc date; wstart = wend, clear span
// elseIf regex chunk warc uri output warc uri; wstart = wend, clear span; skip ahead 300
// ElseIf end of window has \n“ < ” Xml = true // any window size where xml is not started
// continue // whatever triggers in this !xml block, always continue
// // page and xml are active
// // only send to output bare text when a [^\n]< or newline is reached
// test where just outputs all the tags or text it finds
// pull out any <.+> sequences or any >.+< sequences
// multibyte conversion, build string of window
//LPCCH readBuffer = { "ab" }; // = buffer[2];
// std::string str2 = str.substr (3,5);
//wstring sub = (wstring)readBuffer.substr(0,5); // substring of buffer
wstring sub = buffer->substr(windowStart, windowSize);
TCHAR converted[64] = { 0 };
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, (LPCCH)&sub, -1, converted, MAXBUFFERSIZE);
//MultiByteToWideChar(CP_ACP, MB_COMPOSITE, (LPCCH)buffer, MAXBUFFERSIZE, converted, 1); // convert between the utf encoding of the file to the utf encoding of windows?
sendToReportWindow(L"windowStart:%d windowEnd:%d char:%s\n", windowStart, windowEnd, converted);
//sendToReportWindow((LPWSTR)buffer[windowStart]);
windowStart = windowEnd;
// //Tags in body. Any chunk size
// Convert chunk to string for regex ? (prepend span array from previous loop)
// if regex chunk tag pattern output pattern, wstart = wend, clear span
// nested tags? no
// windowEnd++; // tests above did not bite. so increment end of window, increasing window size
} // inner loop: while windowEnd <buffersize
// end of buffer: load any unused window into span
//If windowEnd != windowStart // window start did not get set to end by regex above
//Span = buffer(start – end)
//file progress indicator
//fileSize / fileRemaining x 0.01 // calculate percentage of file remaining with each buffer load
//print progress
//windowStart = 0; windowEnd = 1; windowSize = 1 // look at smaller pieces after first iteration (not in w header)
} // outer loop. while fileRemaining
delete buffer;
【问题讨论】:
-
注意:
TCHAR* buffer = new TCHAR[MAXBUFFERSIZE];定义了一个名为buffer的全新变量,它与之前名为 buffer 的变量无关。如果您想使用现有的buffer,请丢失TCHAR *。如果您不想使用现有的buffer,那么...祝您调试愉快。 -
buffer一个指针,可能用作字符数组。这不是std::string类对象。 -
你有 TCHAR* 缓冲区;并想调用 buffer->substr(windowStart, windowSize) ?但是那个 TCHAR 可能没有像 substr 这样的方法,但可能是 wchar_t 的 typedef
-
而且比这更糟糕,因为
buffer甚至没有被初始化。当您分配内存时,您定义 new 变量,其名称 shadows 在外部范围内的buffer变量。也许您可能需要退后一步,重新了解一些 C++ 基础知识? -
关于
TCHAR的注释:TCHAR是解决老问题的方法,现在应该避免使用。回到世纪之交,微软有两条操作系统系列。一种使用 ANSI 字符,另一种使用 Unicode。大约 15 年前,Windows XP 几乎消灭了 ANSI 系列操作系统。除非您编写的代码必须支持 Windows 95 和现代 Windows 操作系统之类的系统,否则请坚持使用所有内容的 wie 字符版本并消除潜在的歧义。
标签: c++ regex winapi xml-parsing large-files