Je travaille sur un lecteur/écrivain pour les fichiers DNG/TIFF. Comme il existe plusieurs options pour travailler avec des fichiers en général (FileInputStream
, FileChannel
, RandomAccessFile
), je me demande quelle stratégie correspondrait à mes besoins.Lire des données dispersées à partir de plusieurs fichiers dans Java
Un fichier DNG/TIFF est une composition de:
- certains (petits blocs) 5-20 (plusieurs dizaines à centaines d'octets)
- très peu (1-3) grands blocs continus de l'image données (jusqu'à 100 MiB)
- plusieurs (peut-être 20 à 50) de très petits blocs (4-16 octets)
La taille du fichier global varie de 15 MiB (données brutes 14 bits compressé) jusqu'à environ 100 MiB (données flottantes non compressées). Le nombre de fichiers à traiter est compris entre 50 et 400.
Il existe deux modèles d'utilisation:
- lire toutes les méta-données de tous les fichiers (tout sauf les données d'image)
- Lire toutes les données d'image de tous les fichiers
Je suis actuellement en utilisant un FileChannel
et en effectuant un map()
pour obtenir un MappedByteBuffer
couvrant l'ensemble du fichier. Cela semble tout à fait inutile si je suis simplement intéressé par la lecture des méta-données. Un autre problème est la libération de la mémoire mappée: lorsque je passe des tranches du tampon mappé pour l'analyse, le MappedByteBuffer
sous-jacent ne sera pas collecté.
J'ai maintenant décidé de copier de plus petits blocs de FileChannel
en utilisant les plusieurs méthodes read()
et de mapper uniquement les grandes régions de données brutes. L'inconvénient est que la lecture d'une valeur unique semble extrêmement complexe, car il n'y a pas readShort()
et articles similaires:
short readShort(long offset) throws IOException, InterruptedException {
return read(offset, Short.BYTES).getShort();
}
ByteBuffer read(long offset, long byteCount) throws IOException, InterruptedException {
ByteBuffer buffer = ByteBuffer.allocate(Math.toIntExact(byteCount));
buffer.order(GenericTiffFileReader.this.byteOrder);
GenericTiffFileReader.this.readInto(buffer, offset);
return buffer;
}
private void readInto(ByteBuffer buffer, long startOffset)
throws IOException, InterruptedException {
long offset = startOffset;
while (buffer.hasRemaining()) {
int bytesRead = this.channel.read(buffer, offset);
switch (bytesRead) {
case 0:
Thread.sleep(10);
break;
case -1:
throw new EOFException("unexpected end of file");
default:
offset += bytesRead;
}
}
buffer.flip();
}
RandomAccessFile
fournit des méthodes utiles comme readShort()
ou readFully()
, mais ne peut pas gérer peu l'ordre des octets endian. Donc, y a-t-il une façon idiomatique de gérer les lectures dispersées d'octets simples et de blocs énormes? Est-ce que le mappage de la mémoire contient un fichier entier de 100 Mio pour juste lire quelques centaines d'octets inutiles ou lents?
Utilisez un seul 'ByteBuffer' pour toutes les lectures. Les créer est plutôt cher. – EJP
La pré-allocation du 'ByteBuffer' ne sera pas possible dans l'application finale car la taille sera dynamique et interdira l'utilisation simultanée. –