Я потратил время, чтобы погрузиться в источник Tomcat, чтобы найти причину этого. Оказывается, что getRealPath
, в дополнение к извлечению системного пути для заданного виртуального пути, также немного работает с кэшем Tomcat.
ПРИМЕЧАНИЕ:
Я знаю, что мое использование разделителя файлов не очень хорошо, но Tomcat достаточно умен, чтобы проверить приведенный выше вызов для получения /bluesModified.wav
. Поэтому, даже если я назову это как @rickz, упомянутое в комментариях, результат будет таким же, и поэтому проблема не в этом.
Проблемы, с которыми я не смог сослаться на файл в в случае следующего вызова
context.getRealPath("/" + "\\bluesModified.wav")
был факт, что в этом случае мы передаем путь к файлу методу, а в случае, если это работает, мы передаем путь к каталогу.
Что происходит, так это то, что вызов getRealPath()
сначала проверяет кеш на наличие ресурса, идентифицируемого webapppath /bluesModified.wav
. Так как он не существует на момент вызова, Tomcat создаст экземпляр класса EmptyResource
, который в основном является оберткой вокруг класса File
и представляет файл, который не существует, и затем будет хранить ссылку на этот файл в кеше.
Проблема здесь в том, что, хотя я создаю файл с правильным виртуальным путем, Tomcat все равно будет иметь этот пустой ресурс, представляющий несуществующий файл в своем кэше. Другими словами, если я ссылаюсь на файл со стороны клиента следующим образом:
http://localhost:8080/AudioSimulator/bluesModified.wav
Tomcat вернет кэшированный ресурс, представляющий пустой файл, что на самом деле означает 404
для клиент, даже если файл существует.
Ожидание в течение 5 секунд, то есть времени жизни записей кэша Tomcat, и затем попытка ссылки на файл приведет к повторной проверке записи кэша и выдаст FileResource
вместо EmptyResource
в этом случае ссылки будут работать нормально.
В этом случае это работает
context.getRealPath("/") + "\\bluesModified.wav"
, поскольку путь кеширования - это каталог, а имя файла просто объединяется. Таким образом, строка, которую я здесь имею, представляет собой просто абсолютный путь к файлу, который я собираюсь создать, без коллизий записей кэша.
Моя ошибка заключалась в том, что getRealPath()
- это просто какой-то "чистый" метод, который будет вернуть строку, которую я могу использовать для создания файлов, хотя на самом деле она имеет побочные эффекты. Эти побочные эффекты не задокументированы, и, хотя я мог бы сделать некоторые вещи неправильно, суть в том, что этот метод не настолько предсказуем, чтобы использовать его при работе с File IO.