【问题标题】:Dcm4che delete study from local archive (dicomdir)Dcm4che 从本地存档中删除研究 (dicomdir)
【发布时间】:2019-06-05 10:57:33
【问题描述】:

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

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

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

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

所以我的问题如下:

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

  • 正如我在删除研究时看到的“dcm4che-tool-dcmdir”(使用该工具),实际发生的是“删除引用文件指定的 DICOM 文件的记录..或目录..来自现有目录的参数通过将其 Record In-use Flag = 0" 设置为文件,以便文件保留在文件系统中。

  • 当我使用 c-find scu 查询存档时,如果我尝试以这种方式删除研究(tool-dicomdir 中的 -d 选项),我可以找到该研究。因此,即使 dicomdir 中的记录被标记为 Inactive,如果我对存档执行 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 工具包进行了一些研究之后,我能够通过 3 个步骤删除一项研究并同步我的 DICOMDIR 并删除 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();
        }
}

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

【问题讨论】:

    标签: dicom dcm4che


    【解决方案1】:

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

    首先,当您说“删除一项研究”时,我假设您确实想从硬盘中删除 DICOM 文件及其在其他(DICOMDIR 或数据库等)位置的引用。

    在 DICOM 中没有办法做到这一点。

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

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

    正如我上面所说的;没有。

    正如我在删除研究(使用该工具)时看到的“dcm4che-tool-dcmdir”,实际发生的是“从现有目录文件中删除引用文件指定的 DICOM 文件的记录.. 或目录.. 参数通过设置它的 Record In-use Flag = 0" 使文件保留在文件系统中。

    这看起来很自然。该命令应该只修改 DICOMDIR 以删除文件。它不应该从硬盘中删除物理文件。

    当我使用 c-find scu 查询存档时,如果我尝试以这种方式删除研究(tool-dicomdir 中的 -d 选项),我可以找到该研究。因此,即使 dicomdir 中的记录被标记为不活动,如果我对存档执行 c-find 查询,我仍然可以获取它。

    我不知道你的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 Loader/Dump 应用程序中加载 DICOMDIR,并查看相关条目是否消失。
    6. 尝试再次查询以了解情况。

    提案 - 2:

    使用 DICOM 命令,实现自定义行为。修改 DICOM 命令的行为(可能是 N-DELETE)以执行您的附加操作。这只有在您可以访问源代码并愿意更改它的情况下才有可能。我个人不推荐这样做,因为:

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

    【讨论】:

    • 感谢您的回复.. 实际上在 dcm4che3 中使用 DcmDir 工具从 DICOMDIR 中删除研究是一个 3 步过程:1)删除(删除引用由 指定的 DICOM 文件的记录来自现有目录文件 的参数,方法是设置其 Record In-use Flag = 0),2) purge(通过设置 Record In-use Flag = 0 从目录文件 中清除没有文件引用的记录)和 3) compact (通过使用 Record In-use Flag != 0 删除记录来压缩现有目录文件 )然后它是安全的,您实际上也可以从硬盘中删除文件
    猜你喜欢
    • 1970-01-01
    • 2023-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多