Подтвердить что ты не робот

Чтение больших файлов в Java

Мне нужен совет от кого-то, кто хорошо знает Java и проблемы с памятью. У меня большой файл (что-то вроде 1.5 ГБ), и мне нужно вырезать этот файл во многих (например, небольших небольших файлах).

Я знаю, как это сделать (используя BufferedReader), но я хотел бы знать, есть ли у вас какие-либо советы относительно памяти или подсказки, как это сделать быстрее.

Мой файл содержит текст, он не двоичный, и у меня около 20 символов в строке.

4b9b3361

Ответ 1

Во-первых, если ваш файл содержит двоичные данные, использование BufferedReader будет большой ошибкой (потому что вы будете преобразовывать данные в String, что не является необходимым и может привести к повреждению данных); вы должны использовать BufferedInputStream. Если это текстовые данные, и вам нужно разбить их по линиям, то использование BufferedReader в порядке (если файл содержит строки разумной длины).

Что касается памяти, не должно быть никаких проблем, если вы используете буфер с приличным размером (я бы использовал по крайней мере 1 МБ, чтобы убедиться, что HD делает в основном последовательное чтение и запись).

Если скорость окажется проблемой, вы можете посмотреть пакеты java.nio - предположительно быстрее, чем java.io,

Ответ 2

Чтобы сохранить память, не делайте ненужного хранения/дублирования данных в памяти (т.е. не назначайте их переменным вне цикла). Просто обработайте вывод сразу, как только начнется ввод.

Не важно, используете ли вы BufferedReader или нет. Это не будет стоить значительно больше памяти, о чем некоторые неявно предлагают. Он достигнет наивысшего уровня лишь в нескольких процентах от производительности. То же самое относится к использованию NIO. Это улучшит масштабируемость, а не использование памяти. Это станет интересным только тогда, когда сотни тем будут работать в одном файле.

Просто прокрутите файл, сразу напишите каждую строку в другой файл по мере чтения, подсчитайте строки и достигните 100, затем переключитесь на следующий файл и т.д.

Пример Kickoff:

String encoding = "UTF-8";
int maxlines = 100;
BufferedReader reader = null;
BufferedWriter writer = null;

try {
    reader = new BufferedReader(new InputStreamReader(new FileInputStream("/bigfile.txt"), encoding));
    int count = 0;
    for (String line; (line = reader.readLine()) != null;) {
        if (count++ % maxlines == 0) {
            close(writer);
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("/smallfile" + (count / maxlines) + ".txt"), encoding));
        }
        writer.write(line);
        writer.newLine();
    }
} finally {
    close(writer);
    close(reader);
}

Ответ 3

Вы можете использовать файлы с отображением памяти через FileChannel.

Обычно для больших файлов намного быстрее. Есть компромиссы производительности, которые могут сделать его медленнее, поэтому YMMV.

Связанный ответ: Java NIO FileChannel и производительность/полезность FileOutputstream

Ответ 4

Это очень хорошая статья: http://java.sun.com/developer/technicalArticles/Programming/PerfTuning/

В целом, для отличной производительности вы должны:

  • Избегайте доступа к диску.
  • Избегайте доступа к базовой операционной системе.
  • Избегайте вызовов методов.
  • Избегайте обработки байтов и символов в отдельности.

Например, чтобы уменьшить доступ к диску, вы можете использовать большой буфер. В статье описаны различные подходы.

Ответ 5

Нужно ли это делать на Java? То есть Нужно ли быть независимым от платформы? Если нет, я бы предложил использовать команду split 'в * nix. Если вы действительно этого хотели, вы можете выполнить эту команду через вашу java-программу. Хотя я не тестировал, я полагаю, что он работает быстрее, чем любая реализация Java IO, которую вы могли бы придумать.

Ответ 7

Да. Я также думаю, что использование read() с такими аргументами, как read (Char [], int init, int end), является лучшим способом для чтения такого большого файла (Например: read (buffer, 0, buffer.length))

И я также столкнулся с проблемой отсутствия значений использования BufferedReader вместо BufferedInputStreamReader для потока входных двоичных данных. Таким образом, использование BufferedInputStreamReader намного лучше в этом подобном случае.

Ответ 8

Не используйте чтение без аргументов. Это очень медленно. Лучше прочитайте его для буфера и быстро переместите его в файл.

Использовать bufferedInputStream, потому что он поддерживает двоичное чтение.

И все.

Ответ 9

Если вы случайно не читаете во всем входном файле, а не читаете его по строкам, то основным ограничением будет скорость диска. Вы можете попробовать начать с файла, содержащего 100 строк, и записать его в 100 разных файлов по одной строке в каждой и заставить механизм запуска работать с количеством строк, записанных в текущий файл. Эта программа будет легко масштабироваться для вашей ситуации.

Ответ 10

package all.is.well;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import junit.framework.TestCase;

/**
 * @author Naresh Bhabat
 * 
Following  implementation helps to deal with extra large files in java.
This program is tested for dealing with 2GB input file.
There are some points where extra logic can be added in future.


Pleasenote: if we want to deal with binary input file, then instead of reading line,we need to read bytes from read file object.



It uses random access file,which is almost like streaming API.


 * ****************************************
Notes regarding executor framework and its readings.
Please note :ExecutorService executor = Executors.newFixedThreadPool(10);

 *  	   for 10 threads:Total time required for reading and writing the text in
 *         :seconds 349.317
 * 
 *         For 100:Total time required for reading the text and writing   : seconds 464.042
 * 
 *         For 1000 : Total time required for reading and writing text :466.538 
 *         For 10000  Total time required for reading and writing in seconds 479.701
 *
 * 
 */
public class DealWithHugeRecordsinFile extends TestCase {

	static final String FILEPATH = "C:\\springbatch\\bigfile1.txt.txt";
	static final String FILEPATH_WRITE = "C:\\springbatch\\writinghere.txt";
	static volatile RandomAccessFile fileToWrite;
	static volatile RandomAccessFile file;
	static volatile String fileContentsIter;
	static volatile int position = 0;

	public static void main(String[] args) throws IOException, InterruptedException {
		long currentTimeMillis = System.currentTimeMillis();

		try {
			fileToWrite = new RandomAccessFile(FILEPATH_WRITE, "rw");//for random write,independent of thread obstacles 
			file = new RandomAccessFile(FILEPATH, "r");//for random read,independent of thread obstacles 
			seriouslyReadProcessAndWriteAsynch();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Thread currentThread = Thread.currentThread();
		System.out.println(currentThread.getName());
		long currentTimeMillis2 = System.currentTimeMillis();
		double time_seconds = (currentTimeMillis2 - currentTimeMillis) / 1000.0;
		System.out.println("Total time required for reading the text in seconds " + time_seconds);

	}

	/**
	 * @throws IOException
	 * Something  asynchronously serious
	 */
	public static void seriouslyReadProcessAndWriteAsynch() throws IOException {
		ExecutorService executor = Executors.newFixedThreadPool(10);//pls see for explanation in comments section of the class
		while (true) {
			String readLine = file.readLine();
			if (readLine == null) {
				break;
			}
			Runnable genuineWorker = new Runnable() {
				@Override
				public void run() {
					// do hard processing here in this thread,i have consumed
					// some time and ignore some exception in write method.
					writeToFile(FILEPATH_WRITE, readLine);
					// System.out.println(" :" +
					// Thread.currentThread().getName());

				}
			};
			executor.execute(genuineWorker);
		}
		executor.shutdown();
		while (!executor.isTerminated()) {
		}
		System.out.println("Finished all threads");
		file.close();
		fileToWrite.close();
	}

	/**
	 * @param filePath
	 * @param data
	 * @param position
	 */
	private static void writeToFile(String filePath, String data) {
		try {
			// fileToWrite.seek(position);
			data = "\n" + data;
			if (!data.contains("Randomization")) {
				return;
			}
			System.out.println("Let us do something time consuming to make this thread busy"+(position++) + "   :" + data);
			System.out.println("Lets consume through this loop");
			int i=1000;
			while(i>0){
			
				i--;
			}
			fileToWrite.write(data.getBytes());
			throw new Exception();
		} catch (Exception exception) {
			System.out.println("exception was thrown but still we are able to proceeed further"
					+ " \n This can be used for marking failure of the records");
			//exception.printStackTrace();

		}

	}
}