【java文本处理】实现一个简单的小说文本阅读器(分页、翻页、页码跳转)

一、目的

  • 读出文本(.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 跳转到最后一页

【java文本处理】实现一个简单的小说文本阅读器(分页、翻页、页码跳转)_第1张图片

2. g (1.2.3…)跳转到规定页码(输入页码超过文本页码范围提示“输入不存在”),q 退出

【java文本处理】实现一个简单的小说文本阅读器(分页、翻页、页码跳转)_第2张图片

三、源代码

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();
		}
	}
}

四、总结

该阅读器实现了简单的翻页功能,由于需要的辅助方法较多,将需要的方法包装成独立的类,通过各类的调用实现最后功能,以免程序臃肿混乱。代码未做很好地整合因而代码量较大,后续会继续优化代码并增加阅读器功能。

你可能感兴趣的:(java编程,编程)