首先需要说明几点:1.long len = rf.length();获得的文件长度,在seek时是从0到len-1的,如果seek了len,那么用read方法返回-1,代表已经到了文件末尾。所以索引是0到length-1
2.用了RandomAccessFile的read方法后,指针会往后移动一个字符,而readline后会移动到下一行的开头,也就是再read就是下一行的开头第一字符。
3.文本文件,末尾是否为空行是有区别的,看图片,前者末行是空行,后者是末行不是空行。这个并不是百度里说的这是文本文件的显示效果而且说这两个文件是一样的,其实这是不对的。区别在于,前者最后的字符为": 6\r\n",而后者最后的字符只是": 6".也就是说只有行与行之间才有\r\n,而第一行的开头没有\r\n,最后一行若不是空行那最后一行末尾也没有\r\n。
现在做练习:
1.用RandomAccessFile正序读取每一行文本
public class everyline {
public static void main(String[] args) throws IOException, IOException {
// TODO Auto-generated method stub
RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");
String line=null;
while((line=rf.readLine())!=null)
{
//System.out.println(line);
System.out.println(new String(line.getBytes("ISO-8859-1"), "gbk"));
}
}
}
这里不能直接System.out.println(line)因为,用RandomAccessFile 的readline方法读取的字符串的编码格式为ISO-8859-1,而后者则为你IDE的编码方式,我的Eclipse的默认编码方式是gbk,所以要设为gbk。读每一行很简单,直接用方法就行。
2.用RandomAccessFile倒序读取每一行文本.这第一个版本while循环里 rf.seek(nextend);不能是 rf.seek(nextend-1);
public class fromendRead {
public static void main(String args[]) {
RandomAccessFile rf = null;
try {
rf = new RandomAccessFile("E:\\databike.txt", "r");
long len = rf.length(); //文件长度
System.out.println("文件开始指针为"+0);
long nextend = len - 1; //指针是从0到length-1
String line;
rf.seek(nextend); //seek到最后一个字符
int c = -1;
while (nextend >= 0) {
c = rf.read();
if (c == '\n') //只有行与行之间才有\r\n,这表示读到每一行上一行的末尾的\n,而执行完read后,
//指针指到了这一行的开头字符
{
line = new String(rf.readLine().getBytes("ISO-8859-1"), "gbk");
//RandomAccessFile的readLine方法读取文本为ISO-8859-1,需要转化为windows默认编码gbk
System.out.println(line);
//nextend--;
}
rf.seek(nextend);//这一句必须在这个位置,如果在nextend--后,那么导致进0循环后去seek-1索引,报异常
//如果在read()以前,那么导致进入0循环时,因为read指针到1,第一行少读取一个字符
if (nextend == 0) {// 当文件指针退至文件开始处,输出第一行
System.out.println(new String(rf.readLine().getBytes("ISO-8859-1"), "gbk"));
}
nextend--;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (rf != null)
rf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
还有第二个版本,就是在循环里小小改动一下,效果是一样的。之所以要改是因为第二个版本好像更符合我的思考方式。这第二个版本while循环里 rf.seek(nextend);可以是是 rf.seek(nextend-1);区别在于后者的循环次数要少一次。
public class fromendREADnew {
public static void main(String args[]) {
RandomAccessFile rf = null;
try {
rf = new RandomAccessFile("E:\\databike.txt", "r");
long len = rf.length(); //文件长度
System.out.println("文件开始指针为"+0);
long nextend = len - 1; //指针是从0到length-1
String line;
rf.seek(nextend); //seek到最后一个字符
int c = -1;
while (nextend >= 0) {
c = rf.read();
if (c == '\n') //只有行与行之间才有\r\n,这表示读到每一行上一行的末尾的\n,而执行完read后,
//指针指到了这一行的开头字符
{
line = new String(rf.readLine().getBytes("ISO-8859-1"), "gbk");
System.out.println(line);
}
if (nextend == 0) {// 当文件指针退至文件开始处,输出第一行
rf.seek(0);//不需要为下次做准备了,但是因为read()方法指针从0到了1,需重置为0
System.out.println(new String(rf.readLine().getBytes("ISO-8859-1"), "gbk"));
}
else
{
rf.seek(nextend-1);//为下一次循环做准备
}
nextend--;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (rf != null)
rf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
但是这两个程序都要求末行不是空行,如果是请手动删除并保存。思路是每一行除了首行之外,前面都是\r\n那么使循环从后往前,一旦读取到\n,便开始读行(因为read到上一行的\n后,指针后移,刚好到下一行的开头字符,这时再读取行,那么便是读取了这一行的所有数据)。
3.读取第一行
public class firstline {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");
String s=rf.readLine();
System.out.println(s);
}
}
4.读取最后一行(末行为空行或不为空行)
末行不为空行时:
public class lastline {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");
long len = rf.length(); //文件长度
long nextend=len-1;
int c = -1;
while (nextend > 0)
{
rf.seek(nextend);
c = rf.read();
if (c == '\n' )
{
String line = new String(rf.readLine().getBytes("ISO-8859-1"), "gbk");
//RandomAccessFile的readLine方法读取文本为ISO-8859-1,需要转化为windows默认编码gbk
//line=rf.readLine();
System.out.println(line);
break;
}
nextend--;//是循环控制条件,跟指针移动没有关系
}
}
}
末行为空行时:加一个flag,如果第一次遇到先置反
public class lastlineEMPTY {
public static void main(String[] args) throws IOException {
RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");
long len = rf.length(); //文件长度
long nextend=len-1;
int c = -1;
boolean b=false;
while (nextend > 0)
{
rf.seek(nextend);
c = rf.read();
if (c == '\n' )
{
if(b==false)
{
b=true;
}
else
{
String line = new String(rf.readLine().getBytes("ISO-8859-1"), "gbk");
System.out.println(line);
break;
}
}
nextend--;
}
rf.close();
}
}
5.读取正序第几行。用计数器判断。
public class frontANY {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");
String line=null;
int count=1;
int want=5;
while((line=rf.readLine())!=null)
{
if(count==want)
System.out.println(new String(line.getBytes("ISO-8859-1"), "gbk"));
count++;
}
}
}
6.读取倒序第几行。只要需求不是最后一行,那么最后一行是不是空行都无所谓,都可以有结果。但如果要的最后一行,而且最后一行是空行,那么需要在if里面再添加判断条件了。
public class backANY {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//假设最后一行不是空行
RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");
long len = rf.length(); //文件长度
long nextend=len-1;
int c = -1;
int count=1;
int want=5;
while (nextend > 0)
{
rf.seek(nextend);
c = rf.read();
if((c == '\n')&count==want)
{
String line = new String(rf.readLine().getBytes("ISO-8859-1"), "gbk");
System.out.println(line);
break;
}
else if(c == '\n')
{
count++;
}
nextend--;
}
}
}
用RandomAccessFile读取文件真的很方便,因为seek方法可以任意seek