我的第一个答案解决了您的问题的问题,并适当地获得输出到您的文本文件。然而,正如我所提到的关于阅读一行文本的while循环以及对两个文件流使用相同的计数器并不十分优雅。一个更准确的方法来做到这一点,这将允许简化调试,将一次一行地读入完整的输入文件,并将每行保存到一个字符串中,同时将您的字符串存储在一个向量中。通过这种方式,您可以一次解析每行需要的文本,并且可以轻松遍历矢量以快速找到您的文本行。您还应该执行检查以确保您的文件存在并且它可以正确打开。
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
int main() {
std::string strTextFileIn("1.txt");
std::ifstream in;
std::string strLine;
std::vector<std::string> vFileContents;
// Open File Stream
in.open(strTextFileIn.c_str(), std::ios_base::in);
// Test To Make Sure It Opened Properly And That It Exists
if (!in.is_open()) {
std::cout << "Failed to open file, check to make sure file exists." << std::endl;
return -1;
} else {
while (!in.eof()) {
// Get Line Of Text And Save To String
std::getline(in, strLine);
// Push String Into Vector
vFileContents.push_back(strLine);
}
}
// Done With File Close File Stream
if (in.is_open()) {
in.close();
}
// Now That We Have Read In The File Contents And Have Saved Each Line Of Text To A String
// And Stored It In Our Container (Vector) We Can Traverse Our Vector To Find Which String
// Matches The Text We Are Looking For Retrive Its Indexed Value And Then Write To Our
// Output File According To Where You Want The Text To Be Written
unsigned index = 0;
const std::string strLookup("Student");
for (unsigned int i = 0; i < vFileContents.size(); i++) {
if (vFileContents[i] == strLookup) {
// Strings Match We Have Our Indexed Value
index = i;
}
}
// We Want To Write Our Line Of Text 1 Line Past Our Index Value As You Have Stated.
std::string strTextFileOut("2.txt");
std::ofstream out;
// Open Our File For Writting
out.open(strTextFileOut.c_str(), std::ios_base::out);
if (!out.is_open()) {
std::cout << "Failed To open file.";
vFileContents.clear();
return -1;
} else {
for (unsigned int i = 1; i <= index; i++) {
out << std::endl; // Write Blank Lines
}
// The Text Or String You Want To Write To File
out << "Input" << std::endl;
}
// Done With File Stream
if (in.is_open()) {
in.close();
}
// Clear Out Vector
vFileContents.clear();
return 0;
} // main
现在,这可以简化多一点通过与各种文件流对象类型的工作创建一个类层次结构,这样你就不必写这样的代码来打开,关闭,检查的有效性,在充分阅读文件或通过一遍又一遍地遍布你需要的地方。这使它成为模块化的。然而,这种结构依赖于其他一些类,例如ExceptionHandler
类和Logger
类。下面是一个小型的多文件应用程序。
stdafx.h注意:并非所有这些包括和定义都会在这里使用,但是这是来自我的一个更大的项目,我只剥离了这里需要的类,但是离开我的标准标题是。我去掉了这个 “stdafx.h中” 唯一的内容是什么,必须处理的OpenGL,OpenAL的,奥格 - Vorbis格式,GLM图书馆&的API
#ifndef STDAFX_H
#define STDAFX_H
#define VC_EXTRALEAN // Exclude Rarely Used Stuff Windows Headers - Windows Only
// Instead of Creating Another File That VS Makes For You "targetver.h"
// I Will Just Append Its Contents Here
#include <SDKDDKVer.h> // Windows Only
#include <Windows.h> // Windows Only
#include <process.h>
#include <tchar.h>
#include <conio.h>
#include <memory>
#include <string>
#include <numeric>
#include <vector>
#include <array>
#include <unordered_map>
#include <queue>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fstream>
#include "ExceptionHandler.h"
namespace pro {
enum ReturnCode {
RETURN_OK = 0,
RETURN_ERROR = 1,
};
extern const unsigned INVALID_UNSIGNED;
extern const unsigned INVALID_UNSIGNED_SHORT;
} // namespace pro
#endif // STDAFX_H
stdafx.cpp
#include "stdafx.h"
namespace pro {
const unsigned INVALID_UNSIGNED = static_cast<const unsigned>(-1);
const unsigned INVALID_UNSIGNED_SHORT = static_cast<const unsigned short>(-1);
} // namespace pro
ExceptionHandler.h
#ifndef EXCEPTION_HANDLER_H
#define EXCEPTION_HANDLER_H
namespace pro {
class ExceptionHandler sealed {
private:
std::string m_strMessage;
public:
explicit ExceptionHandler(const std::string& strMessage, bool bSaveInLog = true);
explicit ExceptionHandler(const std::ostringstream& strStreamMessage, bool bSavedInLog = true);
// ~ExceptionHandler(); // Default Okay
// ExeptionHandler(const ExceptionHandler& c); // Default Copy Constructor Okay & Is Needed
const std::string& getMessage() const;
private:
ExceptionHandler& operator=(const ExceptionHandler& c); // Not Implemented
}; // ExceptionHandler
} // namespace pro
#endif // EXCEPTION_HANDLER_H
ExceptionHandler.cpp
#include "stdafx.h"
#include "ExceptionHandler.h"
#include "Logger.h"
namespace pro {
ExceptionHandler::ExceptionHandler(const std::string& strMessage, bool bSaveInLog) :
m_strMessage(strMessage) {
if (bSavedInLog) {
Logger::log(m_strMessage, Logger::TYPE_ERROR);
}
}
ExceptionHandler::ExceptionHandler(const std::ostringstream& strStreamMessage, bool bSaveInLog) :
m_strMessage(strStreamMessage.str()) {
if (bSaveInLog) {
Logger::log(m_strMessage, Logger::TYPE_ERROR);
}
}
const std::string& ExceptionHandler::getMessage() const {
return m_strMessage;
}
} // namespace pro
BlockThread.h - 需要记录器
#ifndef BLOCK_THREAD_H
#define BLOCK_THREAD_H
namespace pro {
class BlockThread sealed {
private:
CRITICAL_SECTION* m_pCriticalSection;
public:
explicit BlockThread(CRITICAL_SECTION& criticalSection);
~BlockThread();
private:
BlockThread(const BlockThread& c); // Not Implemented
BlockThread& operator=(const BlockThread& c); // Not Implemented
}; // BlockThread
} // namespace pro
#endif // BLOCK_THREAD_H
BlockThread.cpp
#include "stdafx.h"
#include "BlockThread.h"
namespace pro {
BlockThread::BlockThread(CRTICAL_SECTION& criticalSection) {
m_pCriticalSection = &criticalSection;
EnterCriticalSection(m_pCriticalSection);
}
BlockThread::~BlockThread() {
LeaveCriticalSection(m_pCriticalSection);
}
} // namespace pro
Logger
是Singleton
因为在应用程序运行时您只需要它的一个实例。
Singleton.h
#ifndef SINGLETON_H
#define SINGLETON_H
namespace pro {
class Singleton {
public:
enum SingletonType {
TYPE_LOGGER = 0, // Must Be First!
// TYPE_SETTINGS,
// TYPE_ENGINE,
};
private:
SingletonType m_eType;
public:
virtual ~Singleton();
protected:
explicit Singleton(SingletonType eType);
void logMemoryAllocation(bool isAllocated) const;
private:
Singleton(const Singleton& c); // Not Implemented
Singleton& operator=(const Singleton& c); // Not Implemented
}; // Singleton
} // namespace pro
#endif // SINGLETON_H
Singleton.cpp
#include "stdafx.h"
#include "Logger.h"
#include "Singleton.h"
//#include "Settings.h"
namespace pro {
struct SingletonInfo {
const std::string strSingletonName;
bool isConstructed;
SingletonInfo(const std::string& strSingletonNameIn) :
strSingletonName(strSingletonNameIn),
isConstructed(false) {}
};
// Order Must Match Types Defined In Singleton::SingletonType enum
static std::array<SingletonInfo, 1> s_aSingletons = { SingletonInfo("Logger") }; /*,
SingletonInfo("Settings") };*/ // Make Sure The Number Of Types Matches The Number In This Array
Singleton::Singleton(SingletonType eType) :
m_eType(eType) {
bool bSaveInLog = s_aSingletons.at(TYPE_LOGGER).isConstructed;
try {
if (!s_aSingletons.at(eType).isConstructed) {
// Test Initialization Order
for (int i = 0; i < eType; ++i) {
if (!s_aSingletons.at(i).isConstructed) {
throw ExceptionHandler(s_aSingletons.at(i).strSingletonName + " must be constructed before constructing " + s_aSingletons.at(eType).strSingletonName, bSaveInLog);
}
}
s_aSingletons.at(eType).isConstructed = true;
/*if (s_aSingletons.at(TYPE_ENGINE).isConstructed &&
Setttings::get()->isDebugLogginEnabled(Settings::DEBUG_MEMORY)) {
logMemoryAllocation(true);
}*/
} else {
throw ExceptionHandler(s_aSingletons.at(eType).strSingletonName + " can only be constructed once.", bSaveInLog);
}
} catch (std::exception&) {
// eType Is Out Of Range
std::ostringstream strStream;
strStream << __FUNCTION__ << " Invalid Singleton Type Specified: " << eType;
throw ExceptionHandler(strStream, bSaveInLog);
}
}
Singleton::~Singleton() {
/*if (s_aSingletons.at(TYPE_ENGINE).isConstructed &&
Settings::get()->isDebugLoggingEnabled(Settings::DEBUG_MEMORY)) {
logMemoryAllocation(false);
}*/
s_aSingletons.at(m_eType).isConstructed = false;
}
void Singleton::logMemoryAllocation(bool isAllocated) const {
if (isAllocated) {
Logger::log("Created " + s_aSingletons.at(m_eType).strSingletonName);
} else {
Logger::log("Destroyed " + s_aSingletons.at(m_eType).strSingletonName);
}
}
} // namespace pro
Logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include "Singleton.h"
namespace pro {
class Logger sealed : public Singleton {
public:
// Number Of Items In Enum Type Must Match The Number
// Of Items And Order Of Items Stored In s_aLogTypes
enum LoggerType {
TYPE_INFO = 0,
TYPE_WARNING,
TYPE_ERROR,
TYPE_CONSOLE,
}; // LoggerType
private:
std::string m_strLogFilename;
unsigned m_uMaxCharacterLength;
std::array<std::string, 4> m_aLogTypes
const std::string m_strUnknownLogType;
HANDLE m_hConsoleOutput;
WORD m_consoleDefualtColor;
public:
explicit Logger(const std::string& strLogFilename);
virtual ~Logger();
static void log(const std::string& strText, LoggerType eLogType = TYPE_INFO);
static void log(const std::ostringstream& strStreamText, LoggerType eLogType = TYPE_INFO);
static void log(const char* szText, LoggerType eLogType = TYPE_INFO);
private:
Logger(const Logger& c); // Not Implemented
Logger& operator=(const Logger& c); // Not Implemented
}; // Logger
} // namespace pro
#endif // LOGGER_H
Logger.cpp
#include "stdafx.h"
#include "Logger.h"
#include "BlockThread.h"
#include "TextFileWriter.h"
namespace pro {
static Logger* s_pLogger = nullptr;
static CRITICAL_SECTION = s_criticalSection;
// White Text On Red Background
static const WORD WHITE_ON_RED = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY | BACKGROUND_RED;
Logger::Logger(const std::string& strLogFilename) :
Singleton(TYPE_LOGGER),
m_strLogFilename(strLogFilename),
m_uMaxCharacterLength(0),
m_strUnknownLogType("UNKNOWN") {
// Order Must Match Types Defined In Logger::Type enum
m_aLogTypes[0] = "Info";
m_aLogTypes[1] = "Warning";
m_aLogTypes[2] = "Error";
m_aLogTypes[3] = ""; // Console
// Find Widest Log Type String
m_uMaxCharacterLength = m_strUnknownLogType.size();
for each(const std::string& strLogType in m_aLogTypes) {
if (m_uMaxCharacterLength < strLogType.size()) {
m_uMaxCharacterLength = strLogType.size();
}
}
InitializeCriticalSection(&s_criticalSection);
BlockThread blockThread(s_criticalSection); // Enter Critical Section
// Start Log File
TextFileWriter file(m_strLogFilename, false, false);
// Prepare Console
m_hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER consoleInfo;
GetConsoleScreenBufferInfo(m_hConsoleOutput, &consoleInfo);
m_consoleDefaultColor = consoleInfo.wAttributes;
s_pLogger = this;
logMemoryAllocation(true);
}
Logger::~Logger() {
logMemoryAllocation(false);
s_pLogger = nullptr;
DeleteCriticalSection(&s_criticalSection);
}
void Logger::log(const std::string& strtext, LoggerType eLogType) {
log(strText.c_str(), eLogType);
}
void Logger::log(const std::string& strText, LoggerType eLogType) {
log(strText.str().c_str(), eLogType);
}
void Logger::log(const char* szText, LoggerType eLogType) {
if (nullptr == s_pLogger) {
std::cout << "Logger has not been initialized, can not log " << szText << std::endl;
return;
}
BlockThread blockThread(s_criticalSection); // Enter Critical Section
std::ostringstream strStream;
// Default White Text On Red Background
WORD textColor = WHITE_ON_RED;
// Chose Log Type Text String, Display "UNKNOWN" If eLogType Is Out Of Range
strStream << std::setfill(' ') << std::setw(s_pLogger->m_uMaxCharacterLength);
try {
if (TYPE_CONSOLE != eLogType) {
strStream << s_pLogger->m_aLogTypes.at(eLogType);
}
if (TYPE_WARNING == eLogType) {
// Yellow
textColor = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN;
} else if (TYPE_INFO == eLogType) {
// Green
textColor = FOREGROUND_GREEN;
} else if (TYPE_CONSOLE == eLogType) {
// Cyan
textColor = FOREGROUND_GREEN | FOREGROUND_BLUE;
}
} catch(...) {
strStream << s_pLogger->m_strUnknownLogType;
}
// Date And Time
if (TYPE_CONSOLE != eLogType) {
SYSTEMTIME time;
GetLocalTime(&time);
strStream << " [" << time.wYear << "."
<< std::setfill('0') << std::setw(2) << time.wMonth << "."
<< std::setfill('0') << std::setw(2) << time.wDay << " "
<< std::setfill(' ') << std::setw(2) << time.wHour << ":"
<< std::setfill('0') << std::setw(2) << time.wMinute << ":"
<< std::setfill('0') << std::setw(2) << time.wSecond << "."
<< std::setfill('0') << std::setw(3) << time.wMilliseconds << "] ";
}
strStream << szText << std::endl;
// Log Message
SetConsoleTextAttribute(s_pLogger->m_hConsoleOutput, textColor);
std::cout << strStream.str();
// Save Message To Log File
try {
TextFileWriter file(s_pLogger->m_strLogFilename, true, false);
file.write(strStream.str());
} catch(...) {
// Not Saved In Log File, Write Message To Console
std::cout << __FUNCTION__ << " failed to write to file: " << strStream.str() << std::endl;
}
// Reset To Default Color
SetConsoleTextAttribute(s_pLogger->m_hConsoleOutput, s_pLogger->m_consoleDefaultColor);
}
} // namespace pro
FileHandler.h - 基类
#ifndef FILE_HANDLER_H
#define FILE_HANDLER_H
namespace pro {
// class AssetStorage; // Not Used Here
class FileHandler {
protected:
// static AssetStorage* m_pAssetStorage; // Not Used Here
std::fstream m_fileStream;
std::string m_strFilePath;
std::string m_strFilenameWithPath;
private:
bool m_bSaveExceptionInLog;
public:
virtual ~FileHandle();
protected:
FileHandler(const std::string& strFilename, bool bSaveExceptionInLog);
void throwError(const std::string& strMessage) const;
void throwError(const std::ostringstream& strStreamMessage) const;
bool getString(std::string& str, bool appendPath);
private:
FileHandler(const FileHandler& c); // Not Implemented
FileHandler& operator=(const FileHandler& c); // Not Implemented
}; // FileHandler
} // namespace pro
#endif // FILE_HANDLER_H
FileHandler.cpp
#include "stdafx.h"
#include "FileHandler.h"
// #include "AssetStorage.h" // Not Used Here
namespace pro {
// AssetStorage* FileHandler::m_pAssetStorage = nullptr; // Not Used Here
FileHandler::FileHandler(const std::string& strFilename, bool bSaveExceptionInLog) :
m_bSaveExceptionInLog(bSaveExceptionInLog),
m_strFilenameWithPath(strFilename) {
/*if (bSaveExceptionInLog && nullptr == m_pAssetStorage) {
m_pAssetStorage = AssetStorage::get();
}*/ // Not Used Here
// Extract Path Info If It Exists
std::string::size_type lastIndex = strFilename.find_last_of("/\\");
if (lastIndex != std::string::npos) {
m_strFilePath = strFilename.substr(0, lastIndex);
}
if (strFilename.empty()) {
throw ExceptionHandler(__FUNCTION__ + std::string(" missing filename", m_bSaveExceptionInLog);
}
}
FileHandler::~FileHandler() {
if (m_fileStream.is_open()) {
m_fileStream.close();
}
}
void FileHandler::throwError(const std::string& strMessage) const {
throw ExceptionHandler("File [" + m_strFilenameWithPath + "] " + strMessage, m_bSaveExceptionInLog);
}
void FileHandler::throwError(const std::ostringstream& strStreamMessage) const {
throwError(strStreamMessage.str());
}
bool FileHandler::getString(std::string& str, bool appendPath) {
m_fileStream.read(&str[0], str.size());
if (m_fileStream.fail()) {
return false;
}
// Trim Right
str.erase(str.find_first_of(char(0)));
if (appendPath && !m_strFilePath.empty()) {
// Add Path If One Exists
str = m_strFilePath + "/" + str;
}
return true;
}
} // namespace pro
现在对于你一直在等待这两个继承的类用于处理文件流。这两个是严格的文本。我的项目中的其他人是TextureFiles,ModelObjectFiles等。我将仅显示TextFileReader & TextFileWriter。
TextFileReader.h
#ifndef TEXT_FILE_READER_H
#define TEXT_FILE_READER_H
#include "FileHandler.h"
namespace pro {
class TextFileReader : public FileHandler {
private:
public:
explicit TextFileReader(const std::string& strFilename);
// virtual ~ TextFileReader(); // Default Okay
std::string readAll() const;
bool readLine(std::string& strLine);
private:
TextFileReader(const TextFileReader& c); // Not Implemented
TextFileReader& operator=(const TextFileReader& c); // Not Implemented
}; // TextFileReader
} // namespace pro
#endif // TEXT_FILE_READER_H
TextFileReader.cpp
#include "stdafx.h"
#include "TextFileReader.h"
namespace pro {
TextFileReader::TextFileReader(const std::string& strFilename) :
FileHandler(strFilename, true) {
m_fileStream.open(m_strFilenameWithPath.c_str(), std::ios_base::in);
if (!m_fileStream.is_open()) {
throwError(__FUNCTION__ + std::string(" can not open file for reading"));
}
std::string TextFileReader::readAll() const {
std::ostringstream strStream;
strStream << m_fileStream.rdbuf();
return strStream.str();
}
bool TextFileReader::readLine(std::string& strLine) {
if (m_fileStream.eof()) {
return false;
}
std::getline(m_fileStream, strLine);
return true;
}
} // namespace pro
TextFileWriter.h
#ifndef TEXT_FILE_WRITER_H
#define TEXT_FILE_WRITER_H
#include "FileHandler.h"
namespace pro {
class TextFileWriter : public FileHandler {
private:
public:
TextFileWriter(const std::string& strFilename, bool bAppendToFile, bool bSaveExceptionInLog = true);
void write(const std::string& str);
private:
TextFileWriter(const TextFileWriter& c); // Not Implemented
TextFileWriter& operator=(const TextFileWriter& c); // Not Implemented
}; // TextFileWriter
} // namespace pro
#endif // TEXT_FILE_WRITER_H
TextFileWriter.cpp
#include "stdafx.h"
#include "TextFileWriter.h"
namespace pro {
TextFileWriter::TextFileWriter(const std::string& strFilename, bool bAppendToFile, bool bSaveExceptionInLog) :
FileHandler(strFilename, bSaveExceptionInLog) {
m_fileStream.open(m_strFilenameWithPath.c_str(),
std::ios_base::out | (bAppendToFile ? std::ios_base::app : std::ios_base::trunc));
if (!m_fileStream.is_open()) {
throwError(__FUNCTION__ + std::string(" can not open file for writing"));
}
}
void TextFileWriter::write(const std::string& str) {
m_fileStream << str;
}
} // namespace pro
我们看到的这个动作的样本。如果你看看Logger
类,你将会看到TextFileWriter的使用。
的main.cpp
#include "stdafx.h"
#include "Logger.h"
#include "TextFileReader.h"
#include "TextFileWriter.h"
int _tmain(int iNumArguments, _TCHAR* pArgumentText[]) {
using namespace pro;
try {
// This Is Using The TextFileWriter & Console Output
// Logger::TYPE_INFO is by default!
Logger logger("logger.txt");
logger.log("Some Info");
logger.log("Error!", Logger::TYPE_ERROR);
logger.log("Warning!", Logger::TYPE_WARNING);
TextFileReader textReaderSingle("logger.txt");
TextFileReader textReaderAll("logger.txt");
std::string strTextSingle;
std::string strTextAll;
textReaderSingle.readLine(strTextSingle);
std::cout << "Read Single Line: << std::endl << strText << std::endl << std::endl;
strTextAll = textReaderAll.readAll();
std::cout << "Read All: " << std::endl << strTextAll << std::endl;
//Check The logger.txt that was generated in your projects folder!
std::cout << "Press any key to quit" << std::endl;
_getch();
} catch (ExceptionHandler& e) {
std::cout << "Exception Thrown: " << e.getMessage() << std::endl;
std::cout << "Press any key to quit" << std::endl;
_getch();
return RETURN_ERROR;
} catch(...) {
std::cout << __FUNCTION__ << " Caught Unknown Exception" << std::endl;
std::cout << "Press any key to quit" << std::endl;
_getch();
return RETURN_ERROR;
}
return RETURN_OK;
}
大部分这项工作是认可的马立克A.克热明斯基,睫毛膏在www.MarekKnows.com。实质上所有这些类对象都是他的;唯一的主要区别是我用我自己的namespace pro
而不是他的。 main
这两个函数都是我自己的工作,第一个单独使用,第二个使用他的库代码。
这是一个已经工作了几年的项目,我对C++语言的大部分高级知识都是由于他的视频教程。这个当前的项目是一个在OpenGL中使用着色器的相当大规模的专业质量的GameEngine。所有这些都是按照他的教程进行输入和调试的。
作为一个主要说明;我也在这里输入了大部分内容,如果编译不正确,可能是由于印刷错误。它自己的源代码是一个可用的应用程序。你在这里看到的是他作品中的一小部分!我愿意接受这个信誉,以积累这些知识来回答这个人的问题,但我不能接受这个信誉作为我自己的工作,以保护马立克和他的版权资料。
通过这种设置,可以非常容易地为不同类型的文件创建自己的文件分析器和多个文件分析器。正如我上面所述,还有两个其他类从FileHandler
继承,我没有显示。如果您希望看到更多这个项目,请访问www.MarekKnows.com并加入社区。
什么不符合你的代码? – 0x499602D2
我的输出文件(2.txt)是空白的。 – Marco
为什么不尝试调试程序?逐行浏览并观察会发生什么。 – crashmstr