Ответ 1
Я считаю, RandomAccessFile
- это то, что вам нужно. Он содержит: RandomAccessFile#seek
и RandomAccessFile#getFilePointer
.
rewind()
- seek(0)
Я пишу программу на Java, которая требует, чтобы я сравнивал данные в 2 файлах. Я должен проверить каждую строку из файла 1 на каждую строку файла 2, и если я найду совпадение, напишите их в третий файл. После того, как я прочитал в конце файла 2, как я reset указатель на начало файла?
public class FiFo {
public static void main(String[] args)
{
FileReader file1=new FileReader("d:\\testfiles\\FILE1.txt");
FileReader file2=new FileReader("d:\\testfiles\\FILE2.txt");
try{
String s1,s2;
while((s1=file1.data.readLine())!=null){
System.out.println("s1: "+s1);
while((s2=file2.data.readLine())!=null){
System.out.println("s2: "+s2);
}
}
file1.closeFile();
file2.closeFile();
}catch (IOException e) {
e.printStackTrace();
}
}
}
class FileReader {
BufferedReader data;
DataInputStream in;
public FileReader(String fileName)
{
try{
FileInputStream fstream = new FileInputStream(fileName);
data = new BufferedReader(new InputStreamReader(fstream));
}
catch (IOException e) {
e.printStackTrace();
}
}
public void closeFile()
{
try{
in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
Я считаю, RandomAccessFile
- это то, что вам нужно. Он содержит: RandomAccessFile#seek
и RandomAccessFile#getFilePointer
.
rewind()
- seek(0)
Думаю, лучше всего поставить каждую строку из файла 1 в HashMap
; то вы можете проверить каждую строку файла 2 для членства в HashMap
, а не читать весь файл один раз для каждой строки файла 1.
Но чтобы ответить на вопрос о том, как вернуться к началу файла, проще всего открыть еще один InputStream
/Reader
.
Очевидно, вы могли бы просто закрыть и снова открыть файл следующим образом:
while((s1=file1.data.readLine())!=null){
System.out.println("s1: "+s1);
FileReader file2=new FileReader("d:\\testfiles\\FILE2.txt");
while((s2=file2.data.readLine())!=null){
System.out.println("s2: "+s2);
//compare s1 and s2;
}
file2.closeFile()
}
Но вы действительно не хотите так поступать, так как время работы этого алгоритма равно O (n 2). если в файле A было 1000 строк, а в файле B - 10000 строк, ваш внутренний цикл выполнялся бы 1,000,000 раз.
Что вам нужно сделать, это прочитать каждую строку и сохранить ее в коллекции, которая позволяет быстро проверять, содержит ли элемент (вероятно, HashSet).
Если вам нужно только проверить, чтобы каждая строка файла 2 находилась в файле 1, вы просто добавляете каждую строку в файл один в HashSet, а затем проверяете, чтобы каждая строка в файле 2 находилась в этом наборе,
Если вам нужно выполнить перекрестное сравнение, где вы найдете каждую строку, которая находится в одном, а не другом, тогда вам понадобятся два набора хэшей, по одному для каждого файла. (Хотя есть трюк, который вы можете сделать, чтобы использовать только один)
Если файлы настолько велики, что у вас недостаточно памяти, тогда ваш оригинальный метод n 2 никогда бы не сработал.
Хорошо, ответ Геннадия С. - то, что я буду использовать для решения вашей проблемы.
Я пишу программу на Java, которая требует, чтобы я сравнивал данные в 2 файлах
однако я бы предпочел не кодировать это снова. Я бы предпочел использовать что-то вроде http://code.google.com/p/java-diff-utils/
Как и другие, вы должны рассмотреть другие подходы к проблеме. Для конкретного вопроса о возврате к предыдущему пункту в файле java.io.FileReader
наследует mark()
и reset()
методы, направленные на достижение этой цели.
Как уже отмечалось, существуют лучшие алгоритмы - исследуйте эти
в стороне:
FileReader не реализует метки и reset, поэтому комментарии trashgod неточны. Вам нужно либо реализовать версию этого (с использованием RandomAccessFile, либо нет), либо обернуть в BufferedReader. Тем не менее, последний будет загружать все это в память, если вы отметите его
Просто быстрый вопрос. не можете ли вы сохранить один объект, указанный в начале файла, и пройти через файл с другим объектом? Затем, когда вы дойдете до конца, просто укажите его на объект в начале файла (потока). Я считаю, что С++ имеет такие механизмы с файловым вводом-выводом (или это потоковый ввод-вывод)
Я считаю, что вы можете просто повторно инициализировать файловый читатель файла 2, и он должен reset его.
Если вы можете четко указать размер вашего файла, вы можете использовать mark (int readAheadLimit) и reset() из класса BufferedReader. Метка метода (int readAhedLimit) добавляет маркер в текущую позицию вашего BufferedReader, и вы можете вернуться к маркеру с помощью reset().
Используя их, вы должны быть осторожными до количества символов, которые нужно читать до reset(), вы должны указать их как аргумент метки функции (int readAhedLimit).
Предполагая предел в 100 символов, ваш код должен выглядеть следующим образом:
class MyFileReader {
BufferedReader data;
int maxNumberOfCharacters = 100;
public MyFileReader(String fileName)
{
try{
FileInputStream fstream = new FileInputStream(fileName);
data = new BufferedReader(new InputStreamReader(fstream));
//mark the current position, in this case the beginning of the file
data.mark(maxNumberOfCharacters);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void resetFile(){
data.reset();
}
public void closeFile()
{
try{
in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
Если вы просто хотите, чтобы reset указатель файла в верхней части файла, повторите инициализацию вашего буферизатора. Я предполагаю, что вы также используете блок try и catch для проверки конца файла.
`//To read from a file.
BufferedReader read_data_file = new BufferedReader(new FileReader("Datafile.dat"));'
Скажем так, как вы определили свой буферный читатель. Итак, вот как вы можете проверить конец файла = null.
boolean has_data= true;
while(has_data)
{
try
{
record = read_data_file.readLine();
delimit = new StringTokenizer(record, ",");
//Reading the input in STRING format.
cus_ID = delimit.nextToken();
cus_name = delimit.nextToken();'
//And keep grabbing the data and save it in appropriate fields.
}
catch (NullPointerException e)
{
System.out.println("\nEnd of Data File... Total "+ num_of_records
+ " records were printed. \n \n");
has_data = false; //To exit the loop.
/*
------> This point is the trouble maker. Your file pointer is pointing at the end of the line.
-->If you want to again read all the data FROM THE TOP WITHOUT RECOMPILING:
Do this--> Reset the buffer reader to the top of the file.
*/
read_data_file = new BufferedReader(new FileReader(new File("datafile.dat")));
}
Повторно инициализируя буферизатор, вы будете reset указатель файла/указатель на верхнюю часть файла, и вам не придется перекомпилировать файл, чтобы установить маркер/указатель файла для начала/вершины файла, Вам нужно повторно инициализировать буферизатор, только если вы не хотите перекомпилировать и снять один и тот же трюк в одном и том же режиме. Но если вы хотите просто запустить цикл один раз, то вам не нужно все это, просто перекомпилировав файл, маркер чтения файла будет установлен в начало/начало файла.