Dcm4che удалить исследование из локального архива (dicomdir) - PullRequest
3 голосов
/ 05 июня 2019

Перефразируя мой оригинальный пост после некоторого исследования в dcm4che3 и протоколе dicom.

Я использую инструментарий dcm4che3 для создания приложения, которое, по сути, будет простым Архивом изображений , способным перенаправлять исследования по требованию в другие модальности. Инструмент также реализует s-store scuслужба для запроса себя, но также и других модальностей.

Требуется периодически и "удалять" исследования из этого локального архива.

Я также новичок в протоколе dicom и dcm4che, поэтому яя пытаюсь понять логику базового dicomdir (используемого dcm4che-tool-dcmqrscp), а также любые доступные службы или методы для удаления исследований.

Поэтому у меня следующие вопросы:

Существуют ли другие способы (или часть протокола) для последовательного удаления исследования (навсегда из записей dicomdir, но также и из файловой системы, если возможно)) из dicomdir?

Код, который я использую для удаления исследования (используя аналогичный подход с опцией -d в dicomdir):

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 и удалить исследования (или файлы) с флагом использования записи = 0 в 3 этапа:

//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 Ответ

2 голосов
/ 10 июня 2019

Я уже объяснил вам это в комментариях (сейчас удалено).Я также указал вам на этот вопрос, в котором обсуждается то же самое.Как я уже говорил в комментариях, это больше касается протокола, чем инструментария.

Во-первых, когда вы говорите «Удалить исследование», я предполагаю, что вы действительно хотите удалить файлы DICOM с жесткого диска с их ссылками вдругие местоположения (DICOMDIR или базы данных и т. д.).

В DICOM это невозможно.

Команда N-DELETE в DICOM не предназначена для этой цели.Как объясняется в этом ответе, вы можете попытаться Управление изменениями объекта обработки изображений IHE Integration Profile.Я никогда не использовал это;извините, я не могу комментировать это далее.

В контексте протокола dicom допустим ли термин: "Удалить исследование"?

Как я уже говорил выше;№.

Как я вижу при удалении исследования (используя инструмент) «dcm4che-tool-dcmdir», на самом деле происходит «удаление записей, ссылающихся на файлы DICOM, указанные в файле .. илиdirectory .. аргументы из существующего файла каталога, установив его флаг использования записи = 0 ", чтобы файлы оставались в файловой системе.

Это кажется естественным.Команда должна просто изменить DICOMDIR для удаления файла.Он не должен удалять физический файл с жесткого диска.

Даже больше, если я пытаюсь удалить исследование таким способом (опция -d в tool-dicomdir), когда я запрашиваю архив с моим c-найти СКА, я могу найти исследование.Поэтому, даже если запись в 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 класс, чтобы сделать это.Я нашел следующий пример кода здесь :

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. Убедитесь, что изменения отражены в ссылках.Запустите запрос к базе данных, чтобы проверить записи.Загрузите DICOMDIR в какое-либо приложение DICOM Loader / Dump и посмотрите, пропали ли соответствующие записи.
  6. Попытайтесь выполнить запрос еще раз, чтобы посмотреть, как он работает.

Предложение - 2:

Используя команды DICOM, реализуйте пользовательское поведение.Измените поведение команды DICOM (может быть N-DELETE), чтобы выполнить ваши дополнительные действия.Это возможно, только если у вас есть доступ к исходному коду и вы хотите его изменить.Лично я не рекомендую это, потому что:

  • В любом случае это не DICOM.
  • Вместо этого вы всегда можете реализовать один и тот же код в своем приложении.
...