Dcm4che 从本地存档 (dicomdir) 中删除研究
Dcm4che delete study from local archive (dicomdir)
在对 dcm4che3 和 dicom 协议进行一些研究后改写我原来的 post。
我正在使用 dcm4che3 工具包构建一个应用程序,该应用程序本质上是一个简单的 Image Archive 能够按需将研究转发给其他 modalities.The 工具还实现了 s-store scu 服务查询本身以及其他方式。
一个要求是能够"delete"定期从这个本地档案中学习。
我也是 dicom 协议和 dcm4che 的新手,所以我试图了解底层 dicomdir(由 dcm4che-tool-dcmqrscp 使用)的逻辑以及用于删除研究的任何可用服务或方法。
所以我的问题如下:
在 dicom 协议的上下文中,术语是否有效:"Delete a study"?
正如我在删除研究(使用该工具)时看到的“dcm4che-tool-dcmdir”,实际发生的是 "delete records referring DICOM files specified by file.. or directory.. arguments from existing directory file by setting its Record In-use Flag = 0",因此文件保留在文件系统中。
如果我尝试以这种方式删除一项研究(tool-dicomdir 中的 -d 选项),当我使用我的 c-find scu 查询存档时,我可以找到研究。因此,即使 dicomdir 中的记录被标记为不活动,如果我对存档执行 c-find 查询,我仍然可以获取它。
如果我尝试从文件系统中手动删除学习文件,我猜 dicomdir 已损坏。
是否有任何其他方法(或协议的一部分)以一致的方式从 dicomdir 中删除一项研究(永久地从 dicomdir 记录,但如果可能,也从文件系统)?
我用来删除研究的代码(在 dicomdir 中使用类似方法和 -d 选项)是:
public void deleteDicomDir(String studyDir) throws IOException {
DcmDir1 main = new DcmDir1();
long start = System.currentTimeMillis();
LOG.info("$$$ Trying to delete dicomdir: " + studyDir);
main.open(new File("C:\dicomrouter_dev\dcmrouter_root\dicomdir"));
main.removeReferenceTo(new File(studyDir));
main.close();
long end = System.currentTimeMillis();
System.out.println();
System.out.println(MessageFormat.format(
rb.getString("deleted"),
num, main.getFile(), (end - start)));
}
"removeReferenceTo()" 方法实际上是在最后调用 DicomDirWritter 方法:
public synchronized boolean deleteRecord(Attributes rec)
throws IOException {
if (rec.getInt(Tag.RecordInUseFlag, 0) == INACTIVE)
return false; // already disabled
for (Attributes lowerRec = readLowerDirectoryRecord(rec);
lowerRec != null;
lowerRec = readNextDirectoryRecord(lowerRec))
deleteRecord(lowerRec);
rec.setInt(Tag.RecordInUseFlag, VR.US, INACTIVE);
markAsDirty(rec);
return true;
}
感谢您的宝贵时间,我期待着任何可以声明这一点的信息
实际上,在对 dicom 协议以及 dcm4che 工具包进行了一些研究之后,我能够删除一项研究并同步我的 DICOMDIR,并通过 3 个步骤删除研究(或文件)并使用 Record In-use Flag = 0:
//delete records referring DICOM files specified by <directory:studyDir> arguments from existing directory file <dicomdir> by setting its Record In-use Flag = 0
public void deleteDicomDir(String studyDir) {
String dicomdir = "C:\dicomrouter_dev\dcmrouter_root\DICOMDIR";
DcmDir1 main = new DcmDir1();
long start = System.currentTimeMillis();
try {
LOG.info("$$$ Trying to delete dicomdir: " + studyDir);
main.open(new File(dicomdir));
int num = 0;
main.removeReferenceTo(new File(studyDir));
main.close();
long end = System.currentTimeMillis();
System.out.println();
System.out.println(MessageFormat.format(
rb.getString("deleted"),
num, main.getFile(), (end - start)));
} catch (IOException ex) {
java.util.logging.Logger.getLogger(DcmDir1.class.getName()).log(Level.SEVERE, null, ex);
} finally {
main.close();
}
}
//purge records without file references from directory file <dicomdir> by setting its Record In-use Flag = 0
public void purgeDicomDir() {
String dicomdir = "C:\dicomrouter_dev\dcmrouter_root\DICOMDIR";
DcmDir1 main = new DcmDir1();
long start = System.currentTimeMillis();
try {
main.open(new File(dicomdir));
int num = main.purge();
main.close();
long end = System.currentTimeMillis();
System.out.println(MessageFormat.format(
rb.getString("purged"),
num, main.getFile(), (end - start)));
} catch (IOException ex) {
java.util.logging.Logger.getLogger(DcmDir1.class.getName()).log(Level.SEVERE, null, ex);
} finally {
main.close();
}
}
//compact existing directory file <dicomdir> by removing records with Record In-use Flag != 0
public void compactDicomDir() {
String fpath = "C:\dicomrouter_dev\dcmrouter_root\DICOMDIR";
File f = new File(fpath);
File bak = new File(fpath + "~");
DcmDir1 main = new DcmDir1();
long start = System.currentTimeMillis();
try {
LOG.info("$$$ Trying to compact dicomdir: " + fpath);
main.compact(f, bak);
long end = System.currentTimeMillis();
System.out.println(MessageFormat.format(
rb.getString("compacted"),
f, bak.length(), f.length(), (end - start)));
} catch (IOException ex) {
java.util.logging.Logger.getLogger(DcmDir1.class.getName()).log(Level.SEVERE, null, ex);
} finally {
main.close();
}
}
然后我也可以安全地从磁盘中删除文件。
我已经在评论中向您解释过(现已删除)。我还向您指出了讨论相同问题的 this 问题。正如我在评论中所说,这更多的是关于协议而不是工具包。
首先,当您说 "Delete a study" 时,我假设您实际上想从硬盘中删除 DICOM 文件及其在其他(DICOMDIR 或数据库等)位置的引用。
在 DICOM 中无法执行此操作。
DICOM 中的 N-DELETE 命令不是用于此目的。如 this answer, you may attempt Imaging Object Change Management IHE 集成配置文件中所述。我从来没有用过那个;很抱歉,我不能再对此发表评论了。
In the context of dicom protocol is it valid the term: "Delete a study"?
正如我上面所说;没有。
As i can see the "dcm4che-tool-dcmdir" when deleting a study (using the tool), what happens actually is to "delete records referring DICOM files specified by file.. or directory.. arguments from existing directory file by setting its Record In-use Flag = 0" so the files remain on the filesystem.
这似乎很自然。该命令应该只修改 DICOMDIR 以删除文件。它不应从硬盘中删除物理文件。
Even more if i try and delete a study in this way (-d option in tool-dicomdir) when i query the archive with my c-find scu, i can find the study. So even if the record in dicomdir is marked as Inactive if i perform a c-find query to the archive i can still fetch it.
我不知道你的来源是什么C-FIND-RESPONSE
。如果它是 DICOMDIR 本身,很可能您在前面的步骤中对其所做的修改没有保存。保存修改,这应该可以工作。但请记住,这仍然不会从物理存储中删除文件。您只是删除了它的引用。
我不是您正在使用的工具包的专家。但是,在您的问题中使用以下代码:
main.open(new File("C:\dicomrouter_dev\dcmrouter_root\dicomdir"));
main.removeReferenceTo(new File(studyDir));
//Check if you need to save the changes here before closing
main.close();
您似乎正在打开 DICOMDIR -- 从中删除目录引用 -- 关闭 DICOMDIR。我不知道 removeReferenceTo
方法的实现;可能是来自 github. If it does not save the changes as well, you have to save the changes explicitly. May be you need to use DicomOutputStream
class to do it. I found following sample code here:
FileOutputStream fos = new FileOutputStream(fileOutput +".dcm");
BufferedOutputStream bos = new BufferedOutputStream(fos);
DicomOutputStream dos = new DicomOutputStream(bos);
dos.writeDicomFile(dio);
dos.close();
If i try and delete study files manually from the filesystem i guess that the dicomdir becomes corrupted.
是;那就对了。为避免这种情况,还要相应地修改 DICOMDIR。物理存储和 DICOMDIR 都应处于一致状态。
提案 - 1:
- 决定应该触发删除的 event/action(C-STORE-SUCCESS 发送到调用应用程序)。您始终知道在您的应用程序中触发了 event/action。
- 手动或通过 DICOM 外部的一些代码删除文件。
- 更新底层引用(DICOMDIR、数据库等)以反映此更改(您在问题中所说的
-d
命令)。
- 保存更改。以防万一您错过了这一步。
- 验证更改是否反映在参考文献中。 运行 查询数据库以检查记录。在某些 DICOM Loader/Dump 应用程序中加载 DICOMDIR 并查看相关条目是否消失。
- 尝试再次查询以查看结果如何。
提案 - 2:
使用 DICOM 命令,实现自定义行为。修改 DICOM 命令的行为(N-DELETE 可能)以执行其他操作。这只有在您可以访问源代码并愿意更改它时才有可能。我个人不推荐这样做,因为:
- 无论如何这都不是 DICOM。
- 您可以随时在您的应用程序中实现相同的代码,而不是这样做。
在对 dcm4che3 和 dicom 协议进行一些研究后改写我原来的 post。
我正在使用 dcm4che3 工具包构建一个应用程序,该应用程序本质上是一个简单的 Image Archive 能够按需将研究转发给其他 modalities.The 工具还实现了 s-store scu 服务查询本身以及其他方式。
一个要求是能够"delete"定期从这个本地档案中学习。
我也是 dicom 协议和 dcm4che 的新手,所以我试图了解底层 dicomdir(由 dcm4che-tool-dcmqrscp 使用)的逻辑以及用于删除研究的任何可用服务或方法。
所以我的问题如下:
在 dicom 协议的上下文中,术语是否有效:"Delete a study"?
正如我在删除研究(使用该工具)时看到的“dcm4che-tool-dcmdir”,实际发生的是 "delete records referring DICOM files specified by file.. or directory.. arguments from existing directory file by setting its Record In-use Flag = 0",因此文件保留在文件系统中。
如果我尝试以这种方式删除一项研究(tool-dicomdir 中的 -d 选项),当我使用我的 c-find scu 查询存档时,我可以找到研究。因此,即使 dicomdir 中的记录被标记为不活动,如果我对存档执行 c-find 查询,我仍然可以获取它。
如果我尝试从文件系统中手动删除学习文件,我猜 dicomdir 已损坏。
是否有任何其他方法(或协议的一部分)以一致的方式从 dicomdir 中删除一项研究(永久地从 dicomdir 记录,但如果可能,也从文件系统)?
我用来删除研究的代码(在 dicomdir 中使用类似方法和 -d 选项)是:
public void deleteDicomDir(String studyDir) throws IOException {
DcmDir1 main = new DcmDir1();
long start = System.currentTimeMillis();
LOG.info("$$$ Trying to delete dicomdir: " + studyDir);
main.open(new File("C:\dicomrouter_dev\dcmrouter_root\dicomdir"));
main.removeReferenceTo(new File(studyDir));
main.close();
long end = System.currentTimeMillis();
System.out.println();
System.out.println(MessageFormat.format(
rb.getString("deleted"),
num, main.getFile(), (end - start)));
}
"removeReferenceTo()" 方法实际上是在最后调用 DicomDirWritter 方法:
public synchronized boolean deleteRecord(Attributes rec)
throws IOException {
if (rec.getInt(Tag.RecordInUseFlag, 0) == INACTIVE)
return false; // already disabled
for (Attributes lowerRec = readLowerDirectoryRecord(rec);
lowerRec != null;
lowerRec = readNextDirectoryRecord(lowerRec))
deleteRecord(lowerRec);
rec.setInt(Tag.RecordInUseFlag, VR.US, INACTIVE);
markAsDirty(rec);
return true;
}
感谢您的宝贵时间,我期待着任何可以声明这一点的信息
实际上,在对 dicom 协议以及 dcm4che 工具包进行了一些研究之后,我能够删除一项研究并同步我的 DICOMDIR,并通过 3 个步骤删除研究(或文件)并使用 Record In-use Flag = 0:
//delete records referring DICOM files specified by <directory:studyDir> arguments from existing directory file <dicomdir> by setting its Record In-use Flag = 0
public void deleteDicomDir(String studyDir) {
String dicomdir = "C:\dicomrouter_dev\dcmrouter_root\DICOMDIR";
DcmDir1 main = new DcmDir1();
long start = System.currentTimeMillis();
try {
LOG.info("$$$ Trying to delete dicomdir: " + studyDir);
main.open(new File(dicomdir));
int num = 0;
main.removeReferenceTo(new File(studyDir));
main.close();
long end = System.currentTimeMillis();
System.out.println();
System.out.println(MessageFormat.format(
rb.getString("deleted"),
num, main.getFile(), (end - start)));
} catch (IOException ex) {
java.util.logging.Logger.getLogger(DcmDir1.class.getName()).log(Level.SEVERE, null, ex);
} finally {
main.close();
}
}
//purge records without file references from directory file <dicomdir> by setting its Record In-use Flag = 0
public void purgeDicomDir() {
String dicomdir = "C:\dicomrouter_dev\dcmrouter_root\DICOMDIR";
DcmDir1 main = new DcmDir1();
long start = System.currentTimeMillis();
try {
main.open(new File(dicomdir));
int num = main.purge();
main.close();
long end = System.currentTimeMillis();
System.out.println(MessageFormat.format(
rb.getString("purged"),
num, main.getFile(), (end - start)));
} catch (IOException ex) {
java.util.logging.Logger.getLogger(DcmDir1.class.getName()).log(Level.SEVERE, null, ex);
} finally {
main.close();
}
}
//compact existing directory file <dicomdir> by removing records with Record In-use Flag != 0
public void compactDicomDir() {
String fpath = "C:\dicomrouter_dev\dcmrouter_root\DICOMDIR";
File f = new File(fpath);
File bak = new File(fpath + "~");
DcmDir1 main = new DcmDir1();
long start = System.currentTimeMillis();
try {
LOG.info("$$$ Trying to compact dicomdir: " + fpath);
main.compact(f, bak);
long end = System.currentTimeMillis();
System.out.println(MessageFormat.format(
rb.getString("compacted"),
f, bak.length(), f.length(), (end - start)));
} catch (IOException ex) {
java.util.logging.Logger.getLogger(DcmDir1.class.getName()).log(Level.SEVERE, null, ex);
} finally {
main.close();
}
}
然后我也可以安全地从磁盘中删除文件。
我已经在评论中向您解释过(现已删除)。我还向您指出了讨论相同问题的 this 问题。正如我在评论中所说,这更多的是关于协议而不是工具包。
首先,当您说 "Delete a study" 时,我假设您实际上想从硬盘中删除 DICOM 文件及其在其他(DICOMDIR 或数据库等)位置的引用。
在 DICOM 中无法执行此操作。
DICOM 中的N-DELETE 命令不是用于此目的。如 this answer, you may attempt Imaging Object Change Management IHE 集成配置文件中所述。我从来没有用过那个;很抱歉,我不能再对此发表评论了。
In the context of dicom protocol is it valid the term: "Delete a study"?
正如我上面所说;没有。
As i can see the "dcm4che-tool-dcmdir" when deleting a study (using the tool), what happens actually is to "delete records referring DICOM files specified by file.. or directory.. arguments from existing directory file by setting its Record In-use Flag = 0" so the files remain on the filesystem.
这似乎很自然。该命令应该只修改 DICOMDIR 以删除文件。它不应从硬盘中删除物理文件。
Even more if i try and delete a study in this way (-d option in tool-dicomdir) when i query the archive with my c-find scu, i can find the study. So even if the record in dicomdir is marked as Inactive if i perform a c-find query to the archive i can still fetch it.
我不知道你的来源是什么C-FIND-RESPONSE
。如果它是 DICOMDIR 本身,很可能您在前面的步骤中对其所做的修改没有保存。保存修改,这应该可以工作。但请记住,这仍然不会从物理存储中删除文件。您只是删除了它的引用。
我不是您正在使用的工具包的专家。但是,在您的问题中使用以下代码:
main.open(new File("C:\dicomrouter_dev\dcmrouter_root\dicomdir"));
main.removeReferenceTo(new File(studyDir));
//Check if you need to save the changes here before closing
main.close();
您似乎正在打开 DICOMDIR -- 从中删除目录引用 -- 关闭 DICOMDIR。我不知道 removeReferenceTo
方法的实现;可能是来自 github. If it does not save the changes as well, you have to save the changes explicitly. May be you need to use DicomOutputStream
class to do it. I found following sample code here:
FileOutputStream fos = new FileOutputStream(fileOutput +".dcm");
BufferedOutputStream bos = new BufferedOutputStream(fos);
DicomOutputStream dos = new DicomOutputStream(bos);
dos.writeDicomFile(dio);
dos.close();
If i try and delete study files manually from the filesystem i guess that the dicomdir becomes corrupted.
是;那就对了。为避免这种情况,还要相应地修改 DICOMDIR。物理存储和 DICOMDIR 都应处于一致状态。
提案 - 1:
- 决定应该触发删除的 event/action(C-STORE-SUCCESS 发送到调用应用程序)。您始终知道在您的应用程序中触发了 event/action。
- 手动或通过 DICOM 外部的一些代码删除文件。
- 更新底层引用(DICOMDIR、数据库等)以反映此更改(您在问题中所说的
-d
命令)。 - 保存更改。以防万一您错过了这一步。
- 验证更改是否反映在参考文献中。 运行 查询数据库以检查记录。在某些 DICOM Loader/Dump 应用程序中加载 DICOMDIR 并查看相关条目是否消失。
- 尝试再次查询以查看结果如何。
提案 - 2:
使用 DICOM 命令,实现自定义行为。修改 DICOM 命令的行为(N-DELETE 可能)以执行其他操作。这只有在您可以访问源代码并愿意更改它时才有可能。我个人不推荐这样做,因为:
- 无论如何这都不是 DICOM。
- 您可以随时在您的应用程序中实现相同的代码,而不是这样做。