Dcm4che从本地存档(dicomdir)中删除研究

时间:2019-06-05 10:57:33

标签: dicom dcm4che

在对dcm4che3和dicom协议进行了一些研究之后,重述了我的原始帖子。

我正在使用dcm4che3工具包来构建一个应用程序,该应用程序本质上将是一个简单的Image Archive,能够根据需要将研究转发到其他方式。该工具还实现了s-store scu服务来查询自身,而且其他方式。

一项要求是能够从此本地档案中定期“删除”研究。

我也是dicom协议和dcm4che的新手,所以我试图理解底层dicomdir(由dcm4che-tool-dcmqrscp使用)的逻辑以及删除研究的任何可用服务或方法。

所以我的问题如下:

  • 在dicom协议的上下文中,“删除研究”一词是否有效?

  • 正如我在删除研究(使用该工具)时看到的“ dcm4che-tool-dcmdir”一样,实际上发生的是“删除引用由file ..或directory ..自变量指定的DICOM文件的记录。现有的目录文件,方法是将其记录在用标志设置为“ 0”,以便文件保留在文件系统中。

  • 当我使用c查找scu查询档案时,如果我尝试以此方式删除研究(工具dicomdir中的-d选项),我可以找到研究 >。因此,即使我对归档文件执行c查找查询,即使dicomdir中的记录被标记为“不活动”,我仍然可以将其提取。

  • 如果我尝试从文件系统中手动删除研究文件,我猜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();
        }
}

然后,我也可以安全地从磁盘中删除文件。

1 个答案:

答案 0 :(得分:2)

我已经在评论中(现在已删除)向您说明了这一点。我还向您指出了this问题,该问题讨论了同一件事。正如我在评论中所说,这更多是关于协议而不是工具包。

第一件事,当您说“删除研究”时,我假设您实际上是想从硬盘上删除DICOM文件,并将其引用放在其他位置(DICOMDIR或数据库等)。

在DICOM中无法做到这一点。

DICOM中的

N-DELETE命令不用于此目的。如this答案中所述,您可以尝试Imaging Object Change Management IHE集成配置文件。我没用过很抱歉,我无法对此进一步评论。

  

在dicom协议的上下文中,“删除研究”一词是否有效?

如上所述,不。

  

正如我在删除研究(使用工具)时所看到的“ dcm4che-tool-dcmdir”一样,实际上发生的是“从现有目录文件中删除引用由file ..或directory ..参数指定的DICOM文件的记录。通过设置其“记录使用中标志= 0”,使文件保留在文件系统中。

这似乎很自然。该命令应只修改DICOMDIR即可删除文件。它不应从硬盘删除物理文件。

  

当我使用c查找scu查询档案时,如果我尝试以此方式删除研究(工具dicomdir中的-d选项),我还能找到研究。因此,即使我对归档文件执行c查找查询,即使dicomdir中的记录被标记为“无效”,我仍然可以将其提取。

我不知道您的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。如果它也没有保存更改,则必须显式保存更改。可能是您需要使用DicomOutputStream类来做到这一点。我发现以下示例代码here

FileOutputStream fos = new FileOutputStream(fileOutput +".dcm");
BufferedOutputStream bos = new BufferedOutputStream(fos);
DicomOutputStream dos = new DicomOutputStream(bos);
dos.writeDicomFile(dio);
dos.close();
  

如果我尝试从文件系统中手动删除研究文件,我猜dicomdir损坏了。

是;那就对了。为避免这种情况,还应相应地修改DICOMDIR。物理存储和DICOMDIR都应处于一致状态。

提案-1:

  1. 确定应触发删除操作的事件/动作(发送给调用应用程序的C-STORE-SUCCESS可能是)。您始终在应用程序中知道事件/操作已触发。
  2. 手动删除文件,或通过DICOM之外的一些代码删除文件。
  3. 更新基础引用(DICOMDIR,数据库等)以反映此更改(您所说的-d命令)。
  4. 保存更改。以防万一您错过此步骤。
  5. 验证更改是否反映在引用中。在数据库上运行查询以检查记录。在某些DICOM加载程序/转储应用程序中加载DICOMDIR,查看相关条目是否消失。
  6. 尝试再次查询以查看其进展。

建议-2:

使用DICOM命令,实现自定义行为。修改DICOM命令的行为(可能为N-DELETE)以执行其他操作。仅当您有权访问源代码并愿意更改它时,才有可能。我个人不建议这样做,因为:

  • 这绝对不是DICOM。
  • 除了这样做,您始终可以在应用程序中实现相同的代码。