1背景
上一篇将选择的文件传入了后台线程中,这一篇继续处理解析文件的。
2 正文
2.1 DicomReader 增加读取文件的方法
c++
#pragma once
#include <memory>
#include <string>
#include <dcmtk/dcmdata/dcfilefo.h>
#include "core/model/Image.h"
#include "core/model/Patient.h"
#include "core/model/Series.h"
#include "core/model/Study.h"
#include "dcmtk/dcmdata/dcdatset.h"
#include "dcmtk/dcmdata/dctagkey.h"
class DicomReader
{
public:
explicit DicomReader();
~DicomReader() = default;
public:
void readFile(const std::string& t_filePath);
bool dataSetExist() const;
std::unique_ptr<Patient> getReadPatient() const;
std::unique_ptr<Study> getReadStudy() const;
std::unique_ptr<Series> getReadSeries() const;
std::unique_ptr<Image> getReadImage() const;
private:
std::string m_filePath;
DcmDataset* m_dataSet;
std::unique_ptr<DcmFileFormat> m_file;
std::string getTagFromDataSet(const DcmTagKey& tagKey) const;
static bool isModalitySupported(const std::string& t_modality);
};
除了存储dcm文件地址,还有dcm信息读取并封装成对应的类,以及读取tag的公用方法。 DcmDataset只能用普通指针,因为类库读取的就是普通的指针。

2.2 DicomReader读取文件的定义
这里先实现读取文件,其他的先写个空的,防止编译报错
c++
#include <memory>
#include <stdexcept>
#include "DicomReader.h"
#include "core/model/Image.h"
#include "core/model/Patient.h"
#include "core/model/Series.h"
#include "core/model/Study.h"
#include "dcmtk/dcmdata/dcfilefo.h"
DicomReader::DicomReader() {}
void DicomReader::readFile(const std::string& t_filePath)
{
m_filePath = t_filePath;
m_file = std::make_unique<DcmFileFormat>();
if (m_file->loadFile(t_filePath.c_str()).bad()) {
m_file.release();
m_dataSet = nullptr;
throw std::runtime_error("Cannot open file !");
}
m_dataSet = m_file->getDataset();
}
bool DicomReader::dataSetExist() const
{
return m_dataSet != nullptr;
}
std::unique_ptr<Patient> DicomReader::getReadPatient() const
{
auto t_patient = std::make_unique<Patient>();
return t_patient;
}
std::unique_ptr<Study> DicomReader::getReadStudy() const
{
auto t_study = std::make_unique<Study>();
return t_study;
}
std::unique_ptr<Series> DicomReader::getReadSeries() const
{
auto t_series = std::make_unique<Series>();
return t_series;
}
std::unique_ptr<Image> DicomReader::getReadImage() const
{
auto t_image = std::make_unique<Image>();
return t_image;
}
std::string DicomReader::getTagFromDataSet(const DcmTagKey& tagKey) const
{
auto t_tag = "";
return t_tag;
}
bool DicomReader::isModalitySupported(const std::string& t_modality)
{
return true;
}
复制文件路径,并读取,如果读取失败则释放,否则读取数据集。

2.3 在controller中调用上面的读取文件
c++
#pragma once
#include <memory>
#include <string>
#include "core/lib/DicomReader.h"
#include "core/model/CoreRepository.h"
class CoreController
{
public:
explicit CoreController();
~CoreController() = default;
public:
void readData(const std::string& t_filePath) const;
private:
std::unique_ptr<DicomReader> m_dicomReader;
std::unique_ptr<CoreRepository> m_coreRepository;
void insertDataInRepo() const;
};
申明DicomReader和CoreRepository独立指针,并申明dmc文件解析方法readData,这个是判断解析解析成功后存储的方法。

定义
c++
#include <exception>
#include <memory>
#include <stdexcept>
#include "CoreController.h"
#include "core/lib/DicomReader.h"
CoreController::CoreController()
{
m_dicomReader = std::make_unique<DicomReader>();
m_coreRepository = std::make_unique<CoreRepository>();
}
void CoreController::readData(const std::string& t_filePath) const
{
try {
m_dicomReader->readFile(t_filePath);
auto flag = m_dicomReader->dataSetExist();
if (flag) {
insertDataInRepo();
} else {
throw std::runtime_error("File not Support!");
}
} catch (std::exception& ex) {
}
}
void CoreController::insertDataInRepo() const {}
调用读取文件的方法,判断文件是否读取成功

2.4 在后台线程循环里调用解析
c++
#include <cstdlib>
#include <mutex>
#include "FilesImporter.h"
#include "qglobal.h"
#include "qobject.h"
FilesImporter::FilesImporter(QObject* parent)
: QThread(Q_NULLPTR)
{
m_coreController = std::make_unique<CoreController>();
}
void FilesImporter::startImporter()
{
m_isWorking = true;
start();
}
void FilesImporter::stopImporter()
{
if (!m_isWorking) {
return;
}
m_isWorking = false;
quit();
wait();
m_filesPaths.clear();
}
void FilesImporter::run()
{
while (m_isWorking) {
importFiles();
}
}
void FilesImporter::addFiles(const QStringList& t_paths)
{
std::lock_guard<QMutex> lock(m_filesMutex);
for (const auto& path : t_paths) {
m_filesPaths.push_back(path);
}
}
void FilesImporter::importFiles()
{
while (!m_filesPaths.empty() && m_isWorking) {
std::lock_guard<QMutex> lock(m_filesMutex);
m_coreController->readData(m_filesPaths.front().toStdString());
m_filesPaths.pop_front();
}
}
解析文件里,先判断是否队列有文件,然后获取锁,并调用文件

ps:要初始化m_coreController,否则后面gdb调试会报错
arduino
Thread 5 "FilesImporter" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff17516c0 (LWP 11151)]
0x0000555555560568 in std::__uniq_ptr_impl<DicomReader, std::default_delete<DicomReader> >::_M_ptr (this=0x0)
at /usr/include/c++/13/bits/unique_ptr.h:199
199 pointer _M_ptr() const noexcept { return std::get<0>(_M_t); }
(gdb) list
194 }
195
196 _GLIBCXX23_CONSTEXPR
197 pointer& _M_ptr() noexcept { return std::get<0>(_M_t); }
198 _GLIBCXX23_CONSTEXPR
199 pointer _M_ptr() const noexcept { return std::get<0>(_M_t); }
200 _GLIBCXX23_CONSTEXPR
201 _Dp& _M_deleter() noexcept { return std::get<1>(_M_t); }
202 _GLIBCXX23_CONSTEXPR
203 const _Dp& _M_deleter() const noexcept { return std::get<1>(_M_t); }
(gdb) bt
#0 0x0000555555560568 in std::__uniq_ptr_impl<DicomReader, std::default_delete<DicomReader> >::_M_ptr (this=0x0)
at /usr/include/c++/13/bits/unique_ptr.h:199
#1 0x000055555556047a in std::unique_ptr<DicomReader, std::default_delete<DicomReader> >::get (this=0x0)
at /usr/include/c++/13/bits/unique_ptr.h:470
#2 0x0000555555560208 in std::unique_ptr<DicomReader, std::default_delete<DicomReader> >::operator-> (this=0x0)
at /usr/include/c++/13/bits/unique_ptr.h:463
#3 0x000055555555fdf3 in CoreController::readData (this=0x0,
t_filePath="/home/ubuntu/xcyxiner/DicomViewer/res/CT_small.dcm")
at /home/ubuntu/xcyxiner/DicomViewer/source/core/controller/CoreController.cpp:19
#4 0x000055555555dcf4 in FilesImporter::importFiles (this=0x5555555c1d20)
at /home/ubuntu/xcyxiner/DicomViewer/source/lib/FilesImporter.cpp:51
#5 0x000055555555db5a in FilesImporter::run (this=0x5555555c1d20)
at /home/ubuntu/xcyxiner/DicomViewer/source/lib/FilesImporter.cpp:35
#6 0x00007ffff6a7c48d in ?? () from /lib/x86_64-linux-gnu/libQt6Core.so.6
#7 0x00007ffff609caa4 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:447
#8 0x00007ffff6129c6c in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78
(gdb) exit


readData 内存地址为0x0
2.5 编译

2.6 gdb断点调试
直接在控制器的解析方法打断点
arduino
break CoreController::readData

还是选同样的文件CT_small.dcm

停在了断点的位置,顺便输出下断点附近的代码

使用p输出下当前文件地址

在一系列step后,总算进入到了readFile

next 到最后一步,没走到异常

输出下m_dataSet

输出下this以及m_file
