赞
踩
接着前面的内容,我们来继续学习Java,我们来了解一下多线程与输入输出
每个Java程序都有一个缺省的主线程。对于Application,主线程是main()方法执行的线索。对于Applet,主线程是浏览器加载并执行Java小程序。要实现多线程,必须在主线程中创建新的线程对象。
Java语言使用Thread类及其子类的对象来表示线程。新建的线程在它的一个完整的生命周期中通常要经历新生、就绪、运行、阻塞和死亡等五种状态。
当用new和某线程的构造方法创建一个新对象后,这个线程对象处于新生状态,此时它有了自己响应的内存空间,并已经被初始化。处于该状态的线程可以通过调用start()方法进入就绪状态。
处于就绪状态的线程已经具备了运行的条件,但尚未得到CPU资源,因而它将进入线程队列排队,等待系统为它分配CPU。一旦获得了CPU资源,该线程就进入运行状态,并自动调用自己的run()方法。此时,它脱离创建它的主线程,独立开始了自己的线程
进入运行状态的线程执行自己的run方法中的代码。遇到下列情况将终止run方法的执行:
一个正在执行的线程在某些特殊情况下,如执行了suspend、join、sleep方法,或等待I/O设备的使用权,那么它将让出CPU并终止自己的执行,进入阻塞状态。阻塞时他就不能进入就绪队列,只有当引起阻塞状态的原因被消除时,线程才可以转入就绪状态,重新进入到线程队列中排队等待CPU资源,以便从原终止处开始继续进行
处于死亡状态的线程将永远不再执行。线程死亡有两个原因:一是正常运行的线程完成了它的全部工作。二是线程被提前强制性地终止了。例如,通过执行stop或destroy方法来终止线程。
示例:
- package 测试;
- import java.util.Calendar;
- class test extends Thread{
- int pauseTime;
- String name;
- public test(int hTime,String hStr) {
- pauseTime=hTime;
- name=hStr;
- }
- public void run() {
- //Calendar是Java系统提供的日期时间类的类型标识符
- Calendar now;
- int hour,minute,second;
- for(int i=1;i<10;i++) {
- try {
- //得到系统时间
- now=Calendar.getInstance();
- //取小时值
- hour=now.get(Calendar.HOUR);
- //取分值
- minute=now.get(Calendar.MINUTE);
- //取秒值
- second=now.get(Calendar.SECOND);
- System.out.println(" "+name+"时间:"+hour+":"+minute+":"+second);
- Thread.sleep(pauseTime);
- }
- catch(Exception e){
- System.out.println(name+":"+"线程错误"+e);
- }
- }
- }
- static public void main(String[] args) {
- //线程A执行一次后睡眠2000毫秒
- test myThread1=new test(2000,"线程A");
- myThread1.start();
- //线程B执行一次后睡眠1000毫秒
- test myThread2=new test(1000,"线程B");
- myThread2.start();
- }
- }

创建线程对象的另一个途径就是实现Runnable接口,而Runnable接口只有一个方法run(),用户新建线程的操作就由这个方法来决定。run()方法必须由实现此接口的类来实现。定义好run()方法之后,当用户程序需要建立新线程时,只要以这个实现了run()方法的类为参数创建系统类Thread的对象,就可以把用户实现的run方法继承过来。
示例:通过创建两个线程实现“Java Now!”与矩形框在屏幕上呈相反方向不停走动。
这个示例需要三个文件:CString.java、CSquare.java、test.java
- #test.java
- package 测试;
- import java.awt.Color;
- import java.awt.BorderLayout;
- import java.awt.Container;
- import java.awt.Dimension;
- import javax.swing.JApplet;
- public class test extends JApplet{
- @Override
- public void init() {
- //得到窗口容器对象
- Container cp=getContentPane();
- //创建JPanel对象
- CString pa=new CString();
- //创建JPanel对象
- CSquare pa1=new CSquare();
- //设置pa对象的尺寸
- pa.setPreferredSize(new Dimension(300,150));
- //设置pa的对象背景颜色
- pa.setBackground(Color.cyan);
- pa1.setPreferredSize(new Dimension(300,150));
- //设置pa1的对象背景颜色
- pa1.setBackground(Color.cyan);
- //cp容器的布局为BorderLayout,添加pa及pa1的对象到cp容器中
- cp.add(pa,BorderLayout.NORTH);
- cp.add(pa1,BorderLayout.SOUTH);
- }
- }
-
- #CString.java
- package 测试;
- import java.awt.Font;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import javax.swing.JPanel;
- public class CString extends JPanel implements Runnable{
- int x=10,y=30;
- //创建字符串对象
- String Message="Java Now!";
- //创建字体对象
- Font f=new Font("TimesRoman",Font.BOLD,24);
- //以这个实现了run()方法的类为参数创建系统类Thread的对象
- //就可以把Runnable的方法继承过来
- Thread th1=new Thread(this);
- public CString() {
- start();
- }
- private void start() {
- th1.start();
- }
- @Override
- public void run() {
- while(true) {
- x=x-40;
- if(x<=0) {
- x=300;
- }
- //repaint()方法调用paint()方法重画字符串
- repaint();
- try {
- Thread.sleep(500);
- }
- catch(InterruptedException e){
- }
- }
- }
- public void paint(Graphics g) {
- super.paint(g);
- Graphics2D g2=(Graphics2D)g;
- g2.setFont(f);
- g2.drawString(Message, x, y);
- }
- }
-
- #CSquare.java
- package 测试;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.geom.Rectangle2D;
- import javax.swing.JPanel;
- public class CSquare extends JPanel implements Runnable{
- int x1,y1,w1,h1;
- Thread th2=new Thread(this);
- public CSquare() {
- x1=5;
- y1=100;
- w1=40;
- h1=40;
- start();
- }
- void start() {
- th2.start();
- }
- @Override
- public void run() {
- while(true) {
- x1=x1+45;
- if(x1>=250)
- x1=0;
- //repaint方法调用paint()方法重新画矩阵框
- repaint();
- try{
- //线程二睡眠500毫秒
- Thread.sleep(500);
- }
- catch(InterruptedException e) {
-
- }
- }
- }
- public void paint(Graphics g) {
- super.paint(g);
- Graphics2D g2=(Graphics2D)g;
- Rectangle2D.Double rec1=new Rectangle2D.Double(x1,y1,w1,h1);
- g2.draw(rec1);
- }
- }

在单CPU计算机上运行多线程程序,或者当线程数多于处理的数目时,势必存在多个线程争用CPU的情况,这时需要提供一种机制来合理的分配CPU,使多个线程有条不紊、无不干扰的工作,这种机制称为调度。在Java运行系统中,由线程调度器对线程按优先级进行调度。线程调度器中写好了相应的调度算法,当有多个线程在同一时刻处于就绪状态时,线程调度器就会选择优先级最高的线程运行。
Java的线程调度算法可分为两种:优先抢占式调度,轮转调度。
在Java系统中,运行的每个线程都有优先级(一个1~10的正整数,数值越大越优先)。未设定优先级的线程取缺省值5。Java线程的优先级设置遵从下述原则:
setPriority(Thread.NORM_PRIORITY+3)
这个值即代表8。示例:
- package 测试;
-
- class test{
- public static void main(String args[]) {
- //创建A线程
- Thread First=new MyThread("A");
- //A线程优先级为1
- First.setPriority(Thread.MIN_PRIORITY);
-
- Thread Second=new MyThread("B");
- Second.setPriority(Thread.NORM_PRIORITY+1);
- Thread Third=new MyThread("C");
- Third.setPriority(Thread.MAX_PRIORITY);
- First.start();
- Second.start();
- Third.start();
- }
- }
- class MyThread extends Thread{
- String message;
- MyThread(String message){
- this.message=message;
- }
- public void run() {
- for(int i=0;i<2;i++) {
- System.out.println(message+" "+getPriority());
- }
- }
- }

输出:
- C 10
- C 10
- A 1
- B 6
- B 6
- A 1
由于Java支持多线程,具有并发功能,从而大大提高了计算机的处理能力,在各线程之间不存在共享资源的情况下,几个线程的执行顺序可以是随机的。但是,当两个或两个以上的线程需要共享同一资源时,线程之间的执行顺序就需要协调,并且在某一线程占用资源时,其他线程就要等待。
可以这么理解,Java第一个线程是一个生产者,第二个线程是一个消费者,中间资源是一个货架。当货架被生产者占用(放货),消费者不能去用。当货架被消费者占用(消费),生产者不能去用,在这个问题中,两个线程要共享货架这一临界资源,需要在某些时刻(货空/货满)协调他们的工作,即货空时消费者应等待,货满时生产者应等待,这种机制在操作系统中称为线程间的同步。在同步机制中,将那些访问临界资源的程序段称为临界区。
在Java中,临界区是用关键字“synchronized”来标注,并通过一个称为监控器的系统软件来管理的。当执行被冠以“synchronized”的程序段即临界区程序时,监控器将这段程序(访问的临界资源)加锁,此时,称该线程占有临界资源,知道这段程序执行完,才释放锁。只有锁被释放后,其他线程才可以访问这些临界资源。用关键字 synchronized 定义临界区的语句形式是:
synchronize (expression) statement
其中,expression 代表类的名字,是可选项。
statement 可以是一个方法;也可以是一个语句或一个语句块。
示例:
- package 测试;
-
- public class test{
- public static void main(String args[]) {
- //h为键控器
- HoldInt h=new HoldInt();
- //生产者
- ProduceInt p=new ProduceInt(h);
- //消费者
- ConsumeInt c=new ConsumeInt(h);
- p.start();
- c.start();
- }
- }
- class HoldInt{
- private int sharedInt;
- //writeAble=true表示生产者线程能产生新数据
- private boolean writeAble=true;
- //临界区程序段,也称为同步方法
- public synchronized void set(int val) {
- while(!writeAble) {
- //生产者线程不能生产新数据时进入等待
- try {
- wait();
- }catch(InterruptedException e) {}
- }
- //生产者被唤醒后继续执行下面的语句
- writeAble=false;
- sharedInt=val;
- notify();
- }
- //同步方法
- public synchronized int get() {
- while(writeAble) {
- //消费者线程不能消费数据时进入等待状态
- try {
- wait();
- }catch(InterruptedException e) {}
- }
- //消费者被唤醒后继续执行下面的语句
- writeAble=true;
- notify();
- return sharedInt;
- }
- }
- //生产者线程
- class ProduceInt extends Thread{
- private HoldInt hi;
- public ProduceInt(HoldInt hiForm) {
- hi=hiForm;
- }
- public void run() {
- for(int i=1;i<=4;i++) {
- hi.set(i);
- System.out.println("产生的新数据是:"+i);
- }
- }
- }
- //消费者线程
- class ConsumeInt extends Thread{
- private HoldInt hi;
- public ConsumeInt(HoldInt hiForm) {
- hi=hiForm;
- }
- public void run() {
- for(int i=1;i<=4;i++) {
- int val=hi.get();
- System.out.println("读到的数据是:"+val);
- }
- }
- }

输出:
- 产生的新数据是:1
- 读到的数据是:1
- 读到的数据是:2
- 产生的新数据是:2
- 产生的新数据是:3
- 产生的新数据是:4
- 读到的数据是:3
- 读到的数据是:4
注解:shareInt就是我们的共享资源,一开始writeAble是true的,在这个程序中,共享数据的shareInt方法set()和get()头部的修饰符 synchronized 使HoldInt的每个对象都有一把锁。当ProduceInt对象调用set方法时,HoldInt对象就被锁定(所以即使是不同线程,ConsumeInt也不能调用HoldInt对象的get方法),若set()方法中的writeAble的值为false,则调用set()方法中的wait()方法,把调用set()方法的ProduceInt对象放到HoldInt对象的等待队列中,并将HoldInt对象的锁打开,使该对象的其他synchronized方法可被调用。这个ProduceInt对象就一直在等待队列中等待,直到被唤醒使他进入就绪状态,等待分配CPU,当Producement对象再次进入运行状态时,就从刚刚的wait往后继续执行,如此往复。
Java系统的每一个线程都属于某一个线程组。采用线程组结构以后,可以对多个线程进行集中管理。比如,可以同时启动、挂起或者终止一个线程组中的全部线程。Java系统专门在java.lang包中提供了ThreadGroup类来实现对线程组的管理功能。
大多数情况下,一个线程属于哪一个线程组是由编译人员在程序中指定的,若编译人员没有指定,则Java系统会自动将这些线程归于“main”线程组。main线程组是java系统启动时创建的。一个线程组不仅可以包含多个线程,而且线程组中还可以包含其他的线程组。
流是数据的有序序列,它既可以是未加工的原始二进制数据,也可以是经过一定编码处理后的符合某种规定格式的特定数据。在Java.io包中,基本输入/输出流类可按读/写数据的不同类型分为两种:字节流和字符流
我们来看个例子:键盘输入数据的存储
- package 测试;
-
- import java.io.BufferedInputStream;
- import java.io.DataInputStream;
- import java.io.IOException;
- public class test{
- public static void main(String args[]) {
- int count;
- byte b[]=new byte[256];
- String str;
- //输入缓冲区流的对象
- BufferedInputStream bis=new BufferedInputStream(System.in);
- //根据输入缓冲区构造字节流输入对象
- DataInputStream in=new DataInputStream(bis);
- try {
- //判断当前输入流是否支持mark和reset方法
- if(in.markSupported()) {
- System.out.println("支持mark");
- System.out.println("输出字符串,按Enter结束");
- //在输入流的当前位置上设置标记,并保留256位
- in.mark(256);
- //读键盘输入的数据到b数组,count得到输入长度
- count=in.read(b);
- System.out.println("读入字符数"+count);
- //将b数组转换为字符串
- str=new String(b,0,count);
- System.out.println("输入的字符串为:"+str);
- //重新回到标记处读取数据
- in.reset();
- //读前两个字符
- in.read(b,0,2);
- str=new String(b,0,2);
- System.out.println("字符串的前两个为:"+str);
- in.reset();
- in.skip(count/2);
- in.read(b,0,count/2);
- str=new String(b,0,count/2);
- System.out.println("字符串的后半段"+str);
- }else {
- System.out.println("不支持mark");
- }
- bis.close();
- in.close();
- }catch(IOException E) {
- System.out.println("发生I/O错误!");
- }
-
- }
- }

输出:
- 支持mark
- 输出字符串,按Enter结束
- sajdflsjadf
- 读入字符数13
- 输入的字符串为:sajdflsjadf
-
- 字符串的前两个为:sa
- 字符串的后半段sjadf
原理:
从键盘读入字符串并由屏幕输出:
- package 测试;
-
- import java.io.*;
- public class test{
- public static void main(String args[]) {
- int count;
- byte b[]=new byte[256];
- //输入缓冲区流对象
- BufferedInputStream in=new BufferedInputStream(System.in);
- //输出缓冲区流对象
- BufferedOutputStream bout=new BufferedOutputStream(System.out);
- //输出流对象
- DataOutputStream out=new DataOutputStream(bout);
- //输出流对象
- PrintStream p=new PrintStream(System.out);
- try {
- p.println("请输入字符串");
- //从键盘读入数据给b数组,count得到b的长度
- count=in.read(b);
- in.close();
- p.println("读入字节数:"+count);
- p.println("输入的字符串为:");
- //将b数组从0位置开始的count长度的字节写到out对象中
- out.write(b,0,count);
- //将缓冲流缓冲区中的数据输出到屏幕上
- bout.flush();
- p.close();
- out.close();
- }catch(IOException e) {
- System.out.println("发生I/O错误!");
- }
- }
- }

输出就不演示了,看执行过程:
创建BufferedInputStream输入缓冲区类in的对象的构造方法中的参数“System.in”是InputStream类的标准输入流,表示从键盘上读入数据到in的对象中,程序通过in.read方法将in的对象数据写入到b数组中。
创建BufferedOutputStream输出流类bout的对象的构造方法中的参数“System.out”是OutputStream类的标准输出流,表示向屏幕输出。
创建DataOutputStream输出流类out的对象的构造方法中的参数“bout”,表示将out的对象与bout的对象组合成输出流链,这样可以实现动态地增加输出流的功能。
程序的运行过程是通过out.write(b,0,count)方法,将b数组的数据输出到out的对象中,再通过组合输出流链将out的对象的数据输出到bout的对象中,当引用bout.flush,系统自动将缓冲输出流的数据写到屏幕上。
PrintStream类是打印输出流。Java的标准输出System.out是PrintStream的子类,通过引用print()方法或println()方法可向屏幕输出不同的数据
示例:利用InputStreamReader类、BufferedReader类、OutputStreamWriter类实现从键盘输入字符串,再输出到屏幕上。利用CharArrayReader类、CharArrayWriter类实现存储器读/写操作
- package 测试;
-
- import java.io.*;
- public class test{
- public static void main(String args[]) {
- char c1[],c2[];
- String str;
- CharArrayReader cin;
- CharArrayWriter cout;
- //将键盘上输入的数据放入到BufferedReader类in的对象中
- InputStreamReader sin=new InputStreamReader(System.in);
- BufferedReader in=new BufferedReader(sin);
- //屏幕输出
- OutputStreamWriter out=new OutputStreamWriter(System.out);
- try {
- System.out.println("请输入一个字符串,请按Enter结束");
- //读入字符串
- str=in.readLine();
- //将字符串转换成字符数组
- c1=str.toCharArray();
- //创建CharArrayReader类cin的对象,并与输入流c1数组绑定
- cin=new CharArrayReader(c1);
- cout=new CharArrayWriter();
- //读cin的对象数据内容到cout的对象中
- //(cin.ready)返回输入流是否是可读信息
- while(cin.ready()) {
- //读cin中的一个字符并写到cout中,读/写指针后移一个字符的位置
- cout.write(cin.read());
- }
- System.out.print("c2=");
- //将cout的对象数据写到字符数组c2中
- c2=cout.toCharArray();
- //用c2字符数组创建字符串对象并打印
- System.out.println(new String(c2));
- System.out.print("将cout的对象数据写入out的对象中,并输出:");
- cout.writeTo(out);
- //强制输出out中的数据到屏幕
- out.flush();
- }catch(IOException E) {
- System.out.println("I/O错误!");
- }
- }
- }

输出:
- 请输入一个字符串,请按Enter结束
- asdfsdfsa
- c2=asdfsdfsa
- 将cout的对象数据写入out的对象中,并输出asdfsdfsa
BufferedReader 类和 InputStreamReader 类都是 Reader 的子类。但由于 InputStreamReader 类的对象每读一次都要用read()方法进行字节和字符的转化,效率很低;而BufferedReader类是具有缓冲功能的字符输入流类,可实现字符、数组和行的高效读取。若要用readLine()方法一次一行地进行读取,需要将 System.in 包装成 BufferedReader 来使用,此时必须用 InputStreamReader 把 System.in 转换成 Reader 。
创建 InputStreamReader 类sin的对象的构造方法的参数是 “System.in” ,创建BufferedReader 类in的对象的构造方法的参数是“sin”,这表示建立sin的对象与in的对象的组合式链接通道。
程序运行过程是将键盘上输入的数据放入到sin的对象中进行字节到字符的转化,并输入到in的对象中,再通过“str=in.readLine()”语句,实现将 in 的对象的数据按行读取并放入 str 中。
CharArrayReader 和 CharArrayWriter 类可以将字符数组当作字符数据输入或输出的来源。根据这个特性,可以将文本文件的内容读入字符数组,对字符数组作随机存储,然后写回文本。
writeTo()方法不能直接将结果输出到屏幕上,本书借助 OutputStreamWriter 类(这个类是字符流到字节流的转换桥梁,它的方法可以将字符转换为字节再写入字节流,从而实现外部输出)来完成。
在计算机系统中,需要长期保留的数据是以文件的形式存放在磁盘、磁带等外部存储设备中的。程序运行时常常要从文件中读取数据,同时也要把需要长期保留的数据写入文件中。我们来介绍Java的文件与目录管理。
Java语言的java.io包中的File类是专门用来管理磁盘文件和目录的。每个File类的对象表示一个磁盘文件或目录,其对象属性中包含了文件或目录的相关信息,如文件或目录的名称、文件的长度、目录中所含文件的个数等。调用File类的方法可以完成对文件或目录的常用管理操作,如创建文件或目录,删除文件或目录,查看文件的有关信息等。
示例:获取文件的文件名、长度、大小等特性:
- package 测试;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.util.Date;
- public class test{
- public static void main(String[] args) {
- String Path;
- //键盘输入
- InputStreamReader din=new InputStreamReader(System.in);
- BufferedReader in=new BufferedReader(din);
- try {
- System.out.print("请输入相对或绝对路径:");
- //读取输入
- Path=in.readLine();
- File f=new File(Path);
- System.out.println("路径:"+f.getParent());
- System.out.println("档案:"+f.getName());
- System.out.println("绝对路径:"+f.getAbsolutePath());
- System.out.println("文件大小:"+f.length());
- System.out.println("是否为文件:"+(f.isFile()?"是":"否"));
- System.out.println("是否为目录:"+(f.isDirectory()?"是":"否"));
- System.out.println("是否为隐藏:"+(f.isHidden()?"是":"否"));
- System.out.println("是否为读取:"+(f.canRead()?"是":"否"));
- System.out.println("是否为写入:"+(f.canWrite()?"是":"否"));
- System.out.println("最后修改时间:"+new Date(f.lastModified()));
- }catch(IOException e) {
- System.out.println("I/O错误!");
- }
- }
- }

这个是读取已经存在的文件,注意,输入路径的时候不要有空格
示例:显示“E:/Java”文件夹的内容
- package 测试;
- import java.io.*;
- import java.util.*;
- public class test{
- public static void main(String[] args) {
- File ListFile[];
- long totalSize=0;
- int FileCount=0, DirectoryCount=0;
- //生成File对象
- File f=new File("E:/Java");
- System.out.println("目录:"+f.getParent()+"\n");
- if(f.exists()!=true) {
- System.out.println(f.getPath()+"不存在!");
- return;
- }
- //若路径为目录
- if(f.isDirectory()) {
- //得到文件列表
- ListFile=f.listFiles();
- for(int i=0;i<ListFile.length;i++) {
- System.out.print((ListFile[i].isDirectory()?"D":"X")+" ");
- System.out.print(new Date(ListFile[i].lastModified())+" ");
- System.out.print(ListFile[i].length()+" ");
- System.out.print(ListFile[i].getName()+"\n");
- if(ListFile[i].isFile())
- FileCount++;
- else
- DirectoryCount++;
- totalSize+=ListFile[i].length();
- }
- }else { //路径为文件时
- System.out.print((f.isDirectory()?"D":"X")+" ");
- System.out.print(new Date(f.lastModified())+" ");
- System.out.print(f.length()+" ");
- System.out.print(f.getName()+"\n");
- FileCount++;
- totalSize+=f.length();
- }
- System.out.println("\n\t\t 目录数:"+DirectoryCount);
- System.out.println("\t\t 文件数:"+FileCount);
- System.out.println("\t\t 总字节:"+totalSize);
-
- }
- }

我的输出:
程序中会经常用到文件的读/写操作。例如,从已经存在的数据文件中读入数据,或者将程序中产生的大量数据写入磁盘文件中。这时我们就需要使用文件输入/输出流类。Java 系统提供的 FileInputStream 类是用于读取文件中的字节数据的字节文件输入流类;FileOutputStream类是用于向文件写入字节数据的字节文件输出流类。
利用字节文件输入/输出流完成磁盘文件的读/写,首先要利用文件名字符串或File对象创建输入输出流,其次是从文件输入/输出流中读/写数据。从文件输入/输出流中读/写数据有以下两种方式:
示例:直接利用 FileInputStream 类和 FileOutputStream 类完成从键盘读入数据写入文件中,再从写入的文件中读出数据打印到屏幕上的操作。
- package 测试;
- import java.io.*;
- public class test{
- public static void main(String[] args) {
- char c;
- int c1;
- //在当前目录下建目录,也可用绝对路径
- File filePath=new File("d:/");
- //若目录不存在,则建之
- if(!filePath.exists())
- filePath.mkdir();
- //在指定目录下建文件类对象
- File f1=new File(filePath,"d1.txt");
- try {
- FileOutputStream fout=new FileOutputStream(f1);
- System.out.println("请输入字符,输入结束按#:");
- //将从键盘输入的字符写入磁盘文件
- while((c=(char)System.in.read())!='#') {
- fout.write(c);
- }
- fout.close();
- System.out.println("\n打印从磁盘读入的数据");
- FileInputStream fin=new FileInputStream(f1);
- //磁盘文件读入程序
- while((c1=fin.read())!=-1) {
- //将从磁盘读入的数据打印到屏幕上(将int变量c1强制转换为char)
- System.out.print((char)c1);
- }
- fin.close();
- }catch(FileNotFoundException e){
- System.out.println(e);
- }catch(IOException e) {
- System.out.println(e);
- }
-
- }
- }

然后就可以通过控制台的输入给文件增加内容。
示例:利用FileInputStream 和 FileOutputStream 输入/输出流,再套接上 DataInputStream 类和 DataOutputStream 类输入/输出流完成文件的读/写操作。本程序是将程序中的数据写到“t1.txt”文件,再从该文件中读出,输出到屏幕上。
- package 测试;
- import java.io.*;
- public class test{
- public static void main(String[] args) {
- boolean lo=true;
- short si=-32768;
- int i=65534;
- long l=134567;
- float f=(float)1.4567;
- double d=3.14159265359;
- String str1="ABCD";
- String str2="Java 语言数学";
- try {
- FileOutputStream fout=new FileOutputStream("t1.txt");
- //文件输出流对象为参数
- DataOutputStream out=new DataOutputStream(fout);
- FileInputStream fin=new FileInputStream("t1.txt");
- DataInputStream in=new DataInputStream(fin);
- //将数据写入t1.txt文件
- out.writeBoolean(lo);
- out.writeShort(si);
- out.writeByte(i);
- out.writeInt(i);
- out.writeLong(l);
- out.writeFloat(f);
- out.writeDouble(d);
- out.writeBytes(str1);
- out.writeUTF(str2);
- out.close();
- //将t1.txt文件的数据读出,并输出到屏幕
- System.out.println("Boolean lo="+in.readBoolean());
- System.out.println("Short si="+in.readShort());
- System.out.println("Byte i="+in.readByte());
- System.out.println("Int i="+in.readInt());
- System.out.println("Long l="+in.readLong());
- System.out.println("Float f="+in.readFloat());
- System.out.println("Double d="+in.readDouble());
- byte b[]=new byte[4];
- in.readFully(b);
- System.out.print("str1=");
- for(int j=0;j<4;j++) {
- System.out.print((char)b[j]);
- }
- System.out.println();
- System.out.println("str2="+in.readUTF());
- in.close();
- }catch(IOException e) {
- System.out.println(e.toString());
- }
- }
- }

输出:
- Boolean lo=true
- Short si=-32768
- Byte i=-2
- Int i=65534
- Long l=134567
- Float f=1.4567
- Double d=3.14159265359
- str1=ABCD
- str2=Java 语言数学
FileReader类和FileWriter类用于读取文件和向文件写入字符数据。
示例:复制文件
- package 测试;
- import java.io.*;
- public class test{
- public static void main(String[] args) {
- String temp;
- //创建File对象
- File sourceFile,targetFile;
- BufferedReader source;
- BufferedWriter target;
- try {
- InputStreamReader din=new InputStreamReader(System.in);
- BufferedReader in=new BufferedReader(din);
- System.out.println("请输入来源文件路径");
- sourceFile=new File(in.readLine());
- source =new BufferedReader(new FileReader(sourceFile));
- System.out.println("请输入目标文件路径");
- targetFile=new File(in.readLine());
- target =new BufferedWriter(new FileWriter(targetFile));
- System.out.print("确定要复制?(y/n)");
- if((in.readLine()).equals("y")) {
- //源文件的内容不为空
- while((temp=source.readLine())!=null) {
- //向目标文件写入
- target.write(temp);
- target.newLine();
- target.flush();
- }
- System.out.println("复制文件完成!!");
- }else {
- System.out.println("复制文件失败!!!");
- return;
- }
- din.close();
- in.close();
- }catch(IOException e) {
- System.out.println("I/O错误!");
- }
- }
- }

测试输出:
- 请输入来源文件路径
- t1.txt
- 请输入目标文件路径
- d:/t2.txt
- 确定要复制?(y/n)y
- 复制文件完成!!
程序中使用了FileReader类输入流链接BufferedReader类缓冲区输入流、FileWriter类输出流链接BufferedWriter类缓冲区输出流的策略,加快了复制文件的速度。
注意flush:
BufferedWriter是缓冲输入流,意思是调用BufferedWriter的write方法时候。数据是先写入到缓冲区里,并没有直接写入到目的文件里。必须调用BufferedWriter的flush()方法。这个方法会刷新一下该缓冲流,也就是会把数据写入到目的文件里。或者你可以调用BufferedWriter的close()方法,该方法会在关闭该输入流之前先刷新一下该缓冲流。也会把数据写入到目的文件里。如果没有在里面的for()循环中添加 bw.flush();这句话,在if 的时候重新 new BufferedWriter(); 就把原来bw(缓冲区)中的覆盖掉了。于是就不能写进文件字符。
前面介绍的文件存取方式属于顺序存储,即只能从文件的起始位置向后顺序读/写。java.io包提供的RandomAccessFile类是随机文件访问类,该类的对象可以引用与文件位置指针有关的成员方法,读/写任意位置的数据,实现对文件的随机读/写操作。文件的随机存取要比顺序存取更灵活。
从键盘输入五个整数并写入文件t3.txt,再从这个文件中随机读出其中的某个数(由键盘输入确定),将它显示在屏幕上,同时允许用户对这个数进行修改。
- package 测试;
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
- import java.io.RandomAccessFile;
- public class test{
- public static void main(String[] args) {
- int num,a;
- long fp;
- try {
- //键盘输入
- InputStreamReader din=new InputStreamReader(System.in);
- BufferedReader in=new BufferedReader(din);
- //建立随机存取文件(以读写方式打开)
- RandomAccessFile rf=new RandomAccessFile("t3.txt", "rw");
- System.out.println("请输入五个整数");
- int b[]=new int[5];
- for(int i=0;i<5;i++) {
- System.out.print("第"+(i+1)+"个数 ");
- //Integer.parseInt将字符串转换为int
- b[i]=Integer.parseInt(in.readLine());
- rf.writeInt(b[i]);
- }
- while(true) {
- //移动文件指针到文件头
- rf.seek(0);
- System.out.println("请输入要显示第几个数(1-5):");
- //读入序号
- num=Integer.parseInt(in.readLine());
- num=num-1;
- //每个整数四个字节,计算移动位置
- fp=(num)*4;
- rf.seek(fp);
- a=rf.readInt();
- System.out.println("第"+(num+1)+"个数是"+a);
- System.out.print("改写此数:");
- b[num]=Integer.parseInt(in.readLine());
- fp=num*4;
- rf.seek(fp);
- //写入文件
- rf.writeInt(b[num]);
- System.out.print("继续吗?(y/n)");
- if((in.readLine()).equals("n"))
- break;
- }
- }catch(Exception e) {
- System.out.println("I/O错误!");
- }
- }
- }

欢迎访问我的博客 is-hash.com
商业转载 请联系作者获得授权,非商业转载 请标明出处,谢谢
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。