We have: a regular mp3 file. Is it possible to read a certain number of bytes, for example 128 from the end of the file, without reading the entire byte stream? Is it possible to overwrite the 128 bytes at the end of the file without overwriting the entire file? Is it possible to remove 128 bytes from the end of the file?

If so, how? This is necessary because I want to write a utility for editing ID3 tags. And there will be a lot of files.

I correctly assumed that if you completely read-change-write each file, will it take longer than changing pieces of data in files?

  • If you are given an exhaustive answer, mark it as correct (a daw opposite the selected answer). - Nicolas Chabanovsky

3 answers 3

If you want to edit tags, then I would recommend not writing a bike, but using mp3agic , so as not to suffer from id3v2, id3v1, etc.

    What you want can be done like this:

    public static byte[] readFileSegment(File file, int index, int count) { RandomAccessFile raf = new RandomAccessFile(file); byte[] buffer = new byte[count]; try { raf.skipBytes(index); raf.readFully(buffer, 0, count); return buffer; } finally { raf.close(); } } 

    Your guess is correct.

      Look at the java.nio.channels.FileChannel class.

       import static org.junit.Assert.*; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.StandardOpenOption; import java.util.Arrays; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.internal.TextListener; import org.junit.rules.TemporaryFolder; import org.junit.runner.JUnitCore; import org.junit.runners.model.InitializationError; public class FileChannelExamples { @Rule public TemporaryFolder tempFolder = new TemporaryFolder(); private File file; @Before public void setup() throws IOException { file = tempFolder.newFile(); // для каждого теста создаем временный файл из 50 байт от 0 до 49 byte[] data = new byte[50]; for ( int i = 0; i < data.length; i++ ) { data[i] = (byte)i; } try ( FileOutputStream out = new FileOutputStream( file ) ) { out.write( data ); } } @Test public void canReadLastTenBytes() throws IOException { ByteBuffer buffer = ByteBuffer.allocate( 4096 ); FileChannel chan = FileChannel.open( file.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE ); // чтение в буфер с позиции 40 (последние 10 байт) chan.read( buffer, 40 ); chan.close(); buffer.flip(); assertArrayEquals( new byte[] {40, 41, 42, 43, 44, 45, 46, 47, 48, 49}, Arrays.copyOfRange( buffer.array(), 0, 10 ) ); } private static byte[] readFileIntoArray( File file ) throws IOException { try ( InputStream in = new FileInputStream( file ) ) { byte[] result = new byte[(int)file.length()]; in.read( result ); return result; } } @Test public void canAppendToFile() throws IOException { FileChannel chan = FileChannel.open( file.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE ); // если записывать после конца файла, данные дописываются chan.position( chan.size() ); chan.write( ByteBuffer.wrap( new byte[] {1, 2, 3, 4, 5} ) ); chan.close(); byte[] fileContent = readFileIntoArray( file ); assertArrayEquals( new byte[] {45, 46, 47, 48, 49, 1, 2, 3, 4, 5}, Arrays.copyOfRange( fileContent, 45, 55 ) ); } @Test public void canTruncate() throws IOException { FileChannel chan = FileChannel.open( file.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE ); // обрезка файла до 40 байт chan.truncate( 40 ); chan.close(); byte[] fileContent = readFileIntoArray( file ); assertEquals( fileContent.length, 40 ); assertArrayEquals( new byte[] {35, 36, 37, 38, 39}, Arrays.copyOfRange( fileContent, 35, 40 ) ); } @Test public void canOverwriteAndAppend() throws IOException { FileChannel chan = FileChannel.open( file.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE ); // при записи, существующие данные перезаписываются // если происходит превышение размера файла, данные дописываются chan.position( chan.size() - 5 ); chan.write( ByteBuffer.wrap( new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} ) ); chan.close(); byte[] fileContent = readFileIntoArray( file ); assertArrayEquals( new byte[] {40, 41, 42, 43, 44, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, Arrays.copyOfRange( fileContent, 40, 55 ) ); } public static void main( String[] args ) throws InitializationError { JUnitCore junit = new JUnitCore(); junit.addListener( new TextListener( System.out ) ); junit.run( FileChannelExamples.class ); } }