?文章的目的為了記錄使用C++?進行QT Widget 開發學習的經歷。臨時學習,完成app的開發。開發流程和要點有些記憶模糊,趕緊記錄,防止忘記。
??相關鏈接:
開源 C++ QT Widget 開發(一)工程文件結構-CSDN博客
開源 C++ QT Widget 開發(二)基本控件應用-CSDN博客
開源 C++ QT Widget 開發(三)圖表--波形顯示器-CSDN博客
開源 C++ QT Widget 開發(四)文件--二進制文件查看編輯-CSDN博客
?
推薦鏈接:
開源 java android app 開發(一)開發環境的搭建-CSDN博客
開源 java android app 開發(二)工程文件結構-CSDN博客
開源 java android app 開發(三)GUI界面布局和常用組件-CSDN博客
開源 java android app 開發(四)GUI界面重要組件-CSDN博客
開源 java android app 開發(五)文件和數據庫存儲-CSDN博客
開源 java android app 開發(六)多媒體使用-CSDN博客
開源 java android app 開發(七)通訊之Tcp和Http-CSDN博客
開源 java android app 開發(八)通訊之Mqtt和Ble-CSDN博客
開源 java android app 開發(九)后臺之線程和服務-CSDN博客
開源 java android app 開發(十)廣播機制-CSDN博客
開源 java android app 開發(十一)調試、發布-CSDN博客
開源 java android app 開發(十二)封庫.aar-CSDN博客
推薦鏈接:
開源C# .net mvc 開發(一)WEB搭建_c#部署web程序-CSDN博客
開源 C# .net mvc 開發(二)網站快速搭建_c#網站開發-CSDN博客
開源 C# .net mvc 開發(三)WEB內外網訪問(VS發布、IIS配置網站、花生殼外網穿刺訪問)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客
開源 C# .net mvc 開發(四)工程結構、頁面提交以及顯示_c#工程結構-CSDN博客
開源 C# .net mvc 開發(五)常用代碼快速開發_c# mvc開發-CSDN博客
本章主要內容:二進制文件查看和編輯工具。
二進制文件的讀寫用途主要體現在需要高效存儲和訪問非文本數據的場景,例如:
數據存儲優化
二進制文件直接以內存中的數據格式存儲,無需進行文本編碼/解碼轉換,可顯著減少存儲空間并提升讀寫效率。例如操作系統、編譯器或圖形處理軟件中的可執行文件、圖片和視頻文件常采用二進制存儲。 ?
隨機訪問需求
二進制文件支持隨機讀寫操作,可直接定位到文件中的特定位置進行數據存取,適用于需要頻繁讀寫或修改文件的場景(如日志記錄、實時數據處理)。
跨平臺兼容性
二進制文件格式與硬件平臺關聯較小,通過約定統一的字節順序和協議,可實現跨平臺數據交換,常見于嵌入式系統、游戲開發等領域。
一、內容介紹 ?
這是一個簡單的二進制文件編輯器,具有:
文件打開和保存功能
二進制數據的十六進制顯示
基本的編輯能力
類似hex編輯器的界面布局
工程比較簡單,只需要修改,mainwindow.h 和 mainwindow.cpp 如下圖。
二、代碼分析
核心功能方法
2.1? 文件打開功能 (on_btnOpen_clicked)
使用QFileDialog選擇文件
讀取二進制文件內容
格式化數據顯示在文本框中
2.2? 文件保存功能 (on_btnClose_clicked)
檢查是否有打開的文件
解析文本框中的格式化數據
寫回二進制文件
2.3? 二進制文件讀寫
readBinaryFile:讀取整個二進制文件
writeBinaryFile:寫入二進制數據到文件
2.4? 數據格式化與解析
formatBinaryData:將二進制數據格式化為十六進制查看格式
每行顯示16字節
顯示偏移地址
8字節一組,中間有間隔
使用大寫十六進制表示
parseBinaryData:將格式化的文本解析回二進制數據
跳過空行和地址部分
提取十六進制字節并轉換
三、所有源碼
3.1? mainwindow.h源碼
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_btnOpen_clicked();void on_btnClose_clicked();private:Ui::MainWindow *ui;QString currentFilePath;QByteArray readBinaryFile(const QString &filePath);bool writeBinaryFile(const QString &filePath, const QByteArray &data);QString formatBinaryData(const QByteArray &data);QByteArray parseBinaryData(const QString &text);
};#endif // MAINWINDOW_H
3.2? mainwindow.cpp源碼
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTextStream>
#include <QRegularExpression>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);currentFilePath = "";
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_btnOpen_clicked()
{QString filePath = QFileDialog::getOpenFileName(this, "打開二進制文件", "", "所有文件 (*.*)");if (filePath.isEmpty()) {return;}currentFilePath = filePath;QByteArray fileData = readBinaryFile(filePath);if (!fileData.isEmpty()) {QString formattedText = formatBinaryData(fileData);ui->txtFile->setPlainText(formattedText);}
}void MainWindow::on_btnClose_clicked()
{if (currentFilePath.isEmpty()) {QMessageBox::warning(this, "警告", "請先打開一個文件");return;}QString textContent = ui->txtFile->toPlainText();QByteArray binaryData = parseBinaryData(textContent);if (writeBinaryFile(currentFilePath, binaryData)) {QMessageBox::information(this, "成功", "文件保存成功");} else {QMessageBox::critical(this, "錯誤", "文件保存失敗");}
}QByteArray MainWindow::readBinaryFile(const QString &filePath)
{QFile file(filePath);if (!file.open(QIODevice::ReadOnly)) {QMessageBox::critical(this, "錯誤", "無法打開文件: " + file.errorString());return QByteArray();}QByteArray data = file.readAll();file.close();return data;
}bool MainWindow::writeBinaryFile(const QString &filePath, const QByteArray &data)
{QFile file(filePath);if (!file.open(QIODevice::WriteOnly)) {QMessageBox::critical(this, "錯誤", "無法寫入文件: " + file.errorString());return false;}qint64 bytesWritten = file.write(data);file.close();return bytesWritten == data.size();
}QString MainWindow::formatBinaryData(const QByteArray &data)
{QString result;QTextStream stream(&result);for (int i = 0; i < data.size(); i += 16) {// 寫入地址(4字節十六進制,前導0)加上冒號和4個空格stream << QString("%1").arg(i, 4, 16, QLatin1Char('0')).toUpper() << ": ";// 寫入前8個字節的數據for (int j = 0; j < 8; j++) {if (i + j < data.size()) {unsigned char byte = static_cast<unsigned char>(data[i + j]);stream << QString("%1").arg(byte, 2, 16, QLatin1Char('0')).toUpper() << " ";} else {stream << " "; // 空白填充}}// 在前8個字節和后8個字節之間添加2個空格的間隔stream << " ";// 寫入后8個字節的數據for (int j = 8; j < 16; j++) {if (i + j < data.size()) {unsigned char byte = static_cast<unsigned char>(data[i + j]);stream << QString("%1").arg(byte, 2, 16, QLatin1Char('0')).toUpper() << " ";} else {stream << " "; // 空白填充}}stream << "\n";}return result;
}
QByteArray MainWindow::parseBinaryData(const QString &text)
{QByteArray result;QStringList lines = text.split('\n');for (const QString &line : lines) {// 跳過空行if (line.trimmed().isEmpty()) {continue;}// 查找冒號的位置來分割地址和數據部分int colonIndex = line.indexOf(':');if (colonIndex == -1) {continue; // 如果沒有冒號,跳過這一行}// 提取數據部分(冒號后的內容)QString dataLine = line.mid(colonIndex + 1).trimmed();// 分割空格分隔的十六進制字節QStringList hexBytes = dataLine.split(' ', QString::SkipEmptyParts);for (const QString &hexByte : hexBytes) {if (hexByte.length() == 2) {bool ok;char byte = static_cast<char>(hexByte.toInt(&ok, 16));if (ok) {result.append(byte);}}}}return result;
}
四、演示效果
打開二進制文件
顯示二進制文件