文件逆序输出及根据行号索取该行内容
来源:互联网 发布:java创建动态数组赋值 编辑:程序博客网 时间:2024/06/11 18:28
一. 起因
年初,一位同学提取了如何实现倒叙输出文件,根据行号索引该行内容,我思考了一下,得出以下二种方案!
二. 方案
1)方案1:(此方案局限性较大,并且耗内存)
准备一个结构体,用来存储每行起始字符的地址以及该行字符的个数(带换行符),遍历此文件,将文件内容存放到堆中(耗内存的原因),在遍历过程中将每行的起始地址与该行大小分别存在准备好的结构体中!最后,倒叙读取结构体的内容,取得相应的行内容,写入文件,即可完成文件逆序输出,并且也可以根据行号索引来获取该行内容
2)方案2:(不耗内存,速率更快)
基本思想与方案一异曲同工,只不过用到文件映射(CreateFileMapping,MapViewOfFile),首先一次性将文件映射到本进程外的内存中,然后分块读取该共享内存的内容,此种方法及源码将在下片中详细介绍,这里就不做过多的叙述了!
三. 详细论述方案一的优缺点
1)优点
A. 只需一次遍历即可实现倒叙输出与按行号索引该行内容(只想到此点)
2)缺点
A. 由于在32为系统中,单进程我们能用到的地址空间仅有大约2G(进程中总地址空间4G, 除去空指针赋值区,64K禁入区,内核模式分区外,可用约2G),所以我们想要申请堆大小被限制在2G内,,加上进程中其他耗费的地址空间,故此方案局限性很大,仅能处理小文件(1G以内)!
B. 在编码过程中一次分配1G的内存空间是非常的不合理的!
C.效率低(一般情况下: 用户申请一段连续的大的内存块比将申请多段小的内存快耗时长)
如:申请一块60M的内存来处理数据比10次,每次处理10M来处理数据的速率低(方案2可以证实)
四.
是不是看到以上致命缺点对后面的内容没有兴趣了,其实我也是,由于不用注重速率了,所以我在此例中用到了新学的知识,oost::Shared_Ptr与Vector的结合使用,有兴趣的朋友可以看下,或者之处我使用之处的不足!
五. 实现方案代码详解
1)数据结构准备
typedef struct LINE_INFO { char *lpLineHead; INT32 LineSize; // contain '\n' }LINE_INFO;<span style="white-space:pre"></span>
typedef struct LOAD_FILE_PARAM { WCHAR wcsFilePathName[MAX_PATH];<span style="white-space:pre"></span> HWND hWnd;<span style="white-space:pre"></span> INT32 MessageID; INT32 Param[4]; }LOAD_FILE_PARAM;
<pre name="code" class="cpp">char *m_lpFileData; vector<boost::shared_ptr<LINE_INFO>> m_LineInfoVector; LARGE_INTEGER m_liFileSize; HLog *m_lpHLog; WCHAR m_wcsReverseFilePath[MAX_PATH];3)供用户使用的接口
LOAD_FILE_PARAM m_LoadFileParam; BOOL AnalysisFile(LOAD_FILE_PARAM *lpLoadFileParam); // asyn BOOL CallBack_AnalysisFile(LOAD_FILE_PARAM *lpLoadFileParam); // syn BOOL ReverseFileData(); // asyn BOOL CallBack_ReverseFileData(); // syn BOOL GetLineInfoByLineIndex(INT32 LineIndex, char csLineBuffer[], INT32 MaxBufferSize); UINT64 GetLineCount();
4)具体实现遍历文件代码
BOOL ReverseFile::CallBack_AnalysisFile(LOAD_FILE_PARAM *lpLoadFileParam){ DWORD tBeginTime = GetTickCount();#pragma region Check Param if (NULL == lpLoadFileParam || 0 == wcslen(lpLoadFileParam->wcsFilePathName)) { m_lpHLog->TraceLog("Error(%s.%d): Param Illegal!\r\n", __FUNCTION__, __LINE__); return FALSE; } if (NULL == lpLoadFileParam->hWnd || lpLoadFileParam->MessageID < WM_USER) { m_lpHLog->TraceLog("Waring(%s.%d): hWnd or MessageID Illegal!\r\n", __FUNCTION__, __LINE__); } WCHAR wcsPathName[MAX_PATH] = {}; _snwprintf_s(wcsPathName, _TRUNCATE, lpLoadFileParam->wcsFilePathName); wcsrchr(wcsPathName, _T('\\'))[1] = _T('\0'); _snwprintf_s(m_wcsReverseFilePath, _TRUNCATE, _T("%sReverse.log"), wcsPathName);#pragma endregion HANDLE hFile = CreateFile(lpLoadFileParam->wcsFilePathName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { m_lpHLog->TraceLog("Error(%s.%d): CreateFile Failed!\r\n", __FUNCTION__, __LINE__); return FALSE; } GetFileSizeEx(hFile, &m_liFileSize); if (m_liFileSize.QuadPart > MaxFileSize) // Over 1G { m_lpHLog->TraceLog("Error(%s.%d): File too Big!\r\n", __FUNCTION__, __LINE__); return FALSE; } m_lpFileData = new char[m_liFileSize.QuadPart]; // low? DWORD RelRead = 0; ReadFile(hFile, m_lpFileData, (DWORD)m_liFileSize.QuadPart, &RelRead, NULL); // low? char *lpHead = m_lpFileData; char *lpTail = m_lpFileData + m_liFileSize.QuadPart; while(lpHead < lpTail) { char *lpErgodic = lpHead; while (*lpErgodic != 0x0A && lpErgodic < lpTail) { lpErgodic++; } if (lpErgodic > lpTail && *lpErgodic != 0x0A) { break; } if (*lpErgodic == 0x0A) { lpErgodic++; } INT32 LineSize = lpErgodic - lpHead; boost::shared_ptr<LINE_INFO> lpLineInfo(new LINE_INFO()); lpLineInfo->lpLineHead = lpHead; lpLineInfo->LineSize = LineSize; m_LineInfoVector.push_back(lpLineInfo); lpHead = lpErgodic; INT32 Progress = INT32(double(lpHead - m_lpFileData) * 100 / m_liFileSize.QuadPart); ::PostMessageA(lpLoadFileParam->hWnd, lpLoadFileParam->MessageID, 0, (LPARAM)Progress); // Low } DWORD tEndTime = GetTickCount(); m_lpHLog->TraceLog("Time is %d\r\n", tEndTime - tBeginTime); return TRUE;}
六.效果展示
(爱好刀塔的朋友(*^__^*) 嘻嘻)
七. 源码地址:http://download.csdn.net/detail/u012158162/9594174
注: 1)由于此源码只是一个范例,故中存在一些Bug,如没有考虑到重入问题,以及存在不合理的强转,都是可以修改及优化的地方!
2)如没有配置Boost库的朋友可以将用到Boost库智能指针的地方用常用指针替换,注意内存释放,防止泄漏!
3)如没有安装VLD的朋友,将头文件件中包含(#include “vld.h”)注释掉即可!
- 文件逆序输出及根据行号索取该行内容
- 统计文件中单词出现的行号及打印出该行内容
- grep 在文件中查找指定的内容,并输出行号 及 获取指定行号的内容
- C语言在文件中查找字符串是否在某行,显示行号和该行内容
- c语言 逆序 输出文件内容
- easyui 根据rowIndex行号 获取该行的值
- C++ Primer笔记 从txt文件中查找某一个单词出现的次数/行号/该行自从出现位置的内容
- C++ Primer笔记 从txt文件中查找某一个单词出现的次数/行号/该行自从出现位置的内容
- python读取文件同时输出行号和内容
- Linux nl --让输出的文件内容自动加上行号
- 按行号输出文件
- 根据给定行号获取plaintextedit内容
- 字符数组内容逆序输出
- 【C】查找关键字所在行,输出位置及该行
- 读取文件 然后逆序输出
- 创建文件,输出文件内容及打开模式
- linux nl 查看文件内容,显示行号
- js实现根据<td>中的文本值确定是否输出该行<tr>
- js,给定一个数,如何求Fibonacci值
- Java匿名对象
- 一个基于python的数据爬虫
- 站在股市的风口,如何买股票(动态规划问题)
- scanf("%c")和getchar
- 文件逆序输出及根据行号索取该行内容
- Stack Overflow requires external JavaScript from another domain, which is blocked or failed to load.
- 数据结构实验之图论六:村村通公路
- java练习(16.08.03)支付问题
- 数据结构实验之串一:KMP简单应用
- 关于A+B+C问题4种语言的解决办法,Java、C语言、C++、Python
- 软件架构师应该知道的 97 件事
- 微软技术支持实习面试
- HDU 2066 一个人的旅行