我的第一個答案解決了您的問題的問題,並適當地獲得輸出到您的文本文件。然而,正如我所提到的關於閱讀一行文本的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