一、目的
- 读出文本(.txt)内容显示至dos命令窗;
- 按规定行数将文本进行分页;
- 在dos下实现文本翻页、页码跳转等功能,形成简单小说阅读器。
二、主要方法
1. RandomAccessFile类
详细用法参考上篇博文:RandomAccessFile简述
RandomAccessFile是Java输入/输出流体系中功能最丰富的文件内容访问类
,既可以读取文件内容,也可以向文件输出数据。与普通的输入/输出流不同的是,RandomAccessFile支持跳到文件任意位置读写数据
,RandomAccessFile对象包含一个记录指针,用以标识当前读写处的位置
,当程序创建一个新的RandomAccessFile对象时,该对象的文件记录指针对于文件头(也就是0处),当读写n个字节后,文件记录指针将会向后移动n个字节。除此之外,RandomAccessFile可以自由移动该记录指针
。
在本文实现的阅读器中,RandomAccessFile中的“指针”
是最核心的工具,用RandomAccessFile中的raf.seek(pos)
方可实现文本内容跳转,用pos=raf.getFilePointer()
实现当前文本内容进度的指针的获取。
2. 动态数组ArrayList
详细使用方法参考:ArrayList的用法 、 动态数组ArrayList常用方法示例
ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处:
- 动态的增加和减少元素
- 实现了ICollection和IList接口
- 灵活的设置数组的大小
ArrayList<Integer> list1=new ArrayList<Integer>();//创建整数型动态数组
list1.add(1);//在数组末尾添加 1
在本文实现的阅读器中,通过RandomAccessFilede类 pos=raf.getFilePointer()
方法获取文本每行末的指针,并将获得的指针存入动态数组ArrayList中,用于实现阅读器功能时调用数组中对应的指针来达到跳转的目的。
三、“阅读器” 功能演示
使用说明:
command key: q(uit) u( p ) d(own) s(tart) e(nd) g(o pages)
new command>
- q(uit) 退出
- u( p ) 向上翻页
- d(own) 向下翻页
- s(tart) 跳转到开头页
- e(nd) 跳转到最后一页
- g(0) 跳转到规定页码
1. u、d上下翻页,s 跳转到开头页,e 跳转到最后一页
2. g (1.2.3…)跳转到规定页码(输入页码超过文本页码范围提示“输入不存在”),q 退出
三、源代码
1. 主函数
Book_R.java
import java.io.*;
import java.awt.*;
/*
* 本案例实现:(调用以下方法)
* 简单文档阅读器
* 为读入的文档标注页码
* 获取每页末指针并存入动态数组,实现上下翻页,翻到第一页/最后一页
* q:退出;u:往上翻页;d:往下翻页;
* s:开头页;e:末尾页;g:跳转到规定页码.
*
*/
public class Book_R
{
public static void main(String[] args)
{
File file=new File(args[0]);
if(args[0].endsWith("txt"))
{
if(!file.exists())
{
System.out.println("此文档不存在!");
System.exit(0);
}
//调用reader类
reader read=new reader();
read.disp(args[0]);
}
else
{
System.out.println("输入错误!(非.txt)");
System.exit(0);
}
}
}
2. 创建 posArray类方法
/*
* 该方法实现:
* 创建动态数组,将输出的每行文本的末尾指针存入数组
* 返回值为获取了文本所有行指针的动态数组
*
*/
import java.io.*;
import java.util.ArrayList;
import java.lang.*;
public class posArray {
public ArrayList<Long> posget(String b) { //方法带参并且有返回值,定义为动态数组类型
ArrayList<Long> pageEnd = new ArrayList<Long>();//创建动态数组pageEnd
String line = null; //行
long pos=0; //定义指针
int page = 0; //页码
int lineCount = 0;
try {
File file=new File(b);//指定文件
RandomAccessFile raf = new RandomAccessFile(file,"r");//以只读方式读取文件
pageEnd.add(lineCount, pos); //将每行指针存入动态数组
while((line= raf.readLine())!=null){//按行读取文档
pos=raf.getFilePointer();//获取该行指针
lineCount++;//累加行
pageEnd.add(lineCount,pos);//将获取的行指针存入数组
line =new String(line.getBytes("8859_1"), "UTF-8");//编码转化
//System.out.println(line);
}
}
catch(Exception e){
//e.printStackTrace(
return pageEnd;//返回动态数组的值
}
}
调用时:
ArrayList<Long> lineArr= new ArrayList<Long>();
posArray array=new posArray();
lineArr=array.posget(s);
3. 创建lineCount类方法
/*
* 该方法实现:
* 计算小说总行数
*/
import java.io.*;
import java.awt.*;
public class lineCount
{
public int count(String a)//构造带参函数
{
File file=new File(a);//指定文件路径
int lineCount=0;
try
{
RandomAccessFile raf = new RandomAccessFile(file,"r");
//按行读小说,累加
while(raf.readLine()!=null)
{
lineCount++;
}
}
catch(Exception e)
{
e.printStackTrace();
}
return lineCount;//返回总行数
}
}
4. 创建reader类方法
/*
* 方法实现:
* 按规定行数将文本进行分页;
* 在dos下实现文本翻页、页码跳转、退出等功能
* q:退出;u:往上翻页;d:往下翻页;
* s:开头页;e:末尾页;g:跳转到规定页码.
*/
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
//构造reader类disp方法(带参s)
public class reader {
public void disp(String s)
{
ArrayList<Long> lineArr= new ArrayList<Long>();//创建长整型动态数组lineArr
//调用posArray类posget方法(带参)
posArray array=new posArray();
lineArr=array.posget(s);
String line = null; //行
long pos = 0; //指针
int page = 0; //页码
int lineCount = 0; //行计数器
int lineSum;//总行数
int endpage;
try {
File file=new File(s);//指定文件路径(命令行参数输入)
RandomAccessFile raf = new RandomAccessFile(file,"r");//构造方法,以只读方式读文件
raf.seek(pos);//跳转到当前指针位置
//规定16行为一页,打印首页
for(int i=0; i<16; i++) {
line = raf.readLine(); //以行读,循环16次
lineCount++;
line=new String(line.getBytes("8859_1"), "UTF-8");//编码转化
System.out.println(line+"\n"); //打印读出的行
}
pos=raf.getFilePointer();//获取指针的位置(指针会随着读字节流的进度移动)
page = lineCount / 16; //16行为一页
System.out.println(" page"+page);//标注页码
System.out.println("\n\ncommand key: q(uit) u(p) d(own) s(tart) e(nd) g(o pages)");
System.out.println("new command > ");
//调用lineCount 的count方法(带参):计算文本总行数
lineCount hlm=new lineCount();
lineSum=hlm.count(s);
//此部分实现输入命令command >
// q:退出;u:往上翻页;d:往下翻页;
// s:开头页;e:末尾页;g:跳转到规定页码.
while(true) {
int command = System.in.read();//键盘输入命令q、u、d、s、e、g
//输入'q':退出
if(command == 'q') {
System.exit(0);
}
//输入'u'上翻页
//当前页码在第一页,上翻仍为第一页,
//则使指针跳到0处,从开头读16行,仍为第一页
else if(command == 'u') {
if(page==1) {
raf.seek(0);
for(int i=0; i<16; i++)
{
line = raf.readLine();
line=new String(line.getBytes("8859_1"), "UTF-8");
System.out.println(line+"\n");
}
pos=raf.getFilePointer();
page = 1;
System.out.println(" page"+page);
command = 0;
System.out.println("new command > ");
}
//当前页非第一页,调用获取行指针的动态数组lineArr找到上一页的开始位置即可
//执行u操作时,指针位于当前页末,要将指针移动到上一页初,中间行数为(page-2) *16
//获得上页开始位置指针,逐行往下读16行即可
else
{
pos = lineArr.get((page-2) *16);
raf.seek(pos);
for(int i=0; i<16; i++)
{
line = raf.readLine();
line=new String(line.getBytes("8859_1"), "UTF-8");
System.out.println(line+"\n");
}
pos=raf.getFilePointer();
page=page-1;
System.out.println(" page"+page);
//System.out.println("\n\ncommand key: q(uit) u(p) d(own) s(tart) e(nd) g(o pages)");
command = 0;
System.out.println("new command > ");
}
}
//执行d操作时,若当前页为最后一页,仍打印出本页
//若阅读文档最后一页不满16行,整除后最后一页被省略,最后一页页码需手动+1
else if(command == 'd') {
if(page==(lineSum/16)+1){
pos=lineArr.get(lineSum-(lineSum%16));//获取最后一页开头位置(总行-最后一页行数)
raf.seek(pos);
for(int i=0; i<(lineSum%16); i++) {
line = raf.readLine();
line=new String(line.getBytes("8859_1"), "UTF-8");
System.out.println(line+"\n");
}
pos=raf.getFilePointer();
page=(lineSum/16)+1;
System.out.println(" page"+page);
command = 0;
System.out.println("new command > ");
}
//当前页非最后一页,下翻从当前指针位置开始,往下读16行即可
else{
raf.seek(pos);
for(int i=0; i<16; i++) {
line = raf.readLine();
line=new String(line.getBytes("8859_1"), "UTF-8");
System.out.println(line+"\n");
}
pos=raf.getFilePointer();
lineCount += 16;
page = lineCount / 16;
System.out.println(" page"+page);
command = 0;
System.out.println("new command > ");
}
}
//执行s操作,指针移动到开头位置(开头指针为0)即可
else if(command == 's'){
raf.seek(0);
lineCount=0;
for(int i=0; i<16; i++) {
line = raf.readLine();
line=new String(line.getBytes("8859_1"), "UTF-8");
lineCount++;
System.out.println(line+"\n");
}
pos=raf.getFilePointer();
page = lineCount / 16;
System.out.println(" page"+page);
command = 0;
System.out.println("new command > ");
}
//执行e操作,获取最后一页开头指针
//总行数减去最后一页行数,指针位置在最后一页开头
else if(command == 'e'){
pos=lineArr.get(lineSum-(lineSum%16));
raf.seek(pos);
for(int i=0; i<(lineSum%16); i++) {
line = raf.readLine();
line=new String(line.getBytes("8859_1"), "UTF-8");
System.out.println(line+"\n");
}
pos=raf.getFilePointer();
page=(lineSum/16)+1;
System.out.println(" page"+page);
command = 0;
System.out.println("new command > ");
}
//执行g操作,找到指针数组中欲跳转页开头行指针即可
else if(command == 'g'){
System.out.println("input page?Exam:1.2.3...");
Scanner scan = new Scanner(System.in);
int jump = scan.nextInt(); //键盘输入欲跳转页码
//跳转到最后一页,此处默认最后一页不满16行
if(jump==(lineSum/16)+1){
pos=lineArr.get(lineSum-(lineSum%16));
raf.seek(pos);
for(int i=0; i<(lineSum%16); i++) {
line = raf.readLine();
line=new String(line.getBytes("8859_1"), "UTF-8");
System.out.println(line+"\n");
}
pos=raf.getFilePointer();
page=(lineSum/16)+1;
System.out.println(" page"+page);
command = 0;
System.out.println("new command > ");
}
//跳转到除最后一页的其他页,从数组中获取当页首行指针:(jump(欲跳转页)-1)*16 行
else if(jump<(lineSum/16)+1){
pos=lineArr.get((jump-1)*16);
raf.seek(pos);
for(int i=0; i<16; i++) {
line = raf.readLine();
line=new String(line.getBytes("8859_1"), "UTF-8");
//lineCount++;
System.out.println(line+"\n");
}
pos=raf.getFilePointer();
page = jump;
System.out.println(" page"+page);
command = 0;
System.out.println("new command > ");
}
//输入页码超过文本页码范围,提示出错
else{
System.out.println("Not Exit!");
command = 0;
System.out.println("new command > ");
}
}
}
}
catch(Exception e){
e.printStackTrace();
}
}
}
四、总结
该阅读器实现了简单的翻页功能,由于需要的辅助方法较多,将需要的方法包装成独立的类,通过各类的调用实现最后功能,以免程序臃肿混乱。代码未做很好地整合因而代码量较大,后续会继续优化代码并增加阅读器功能。