黑马程序员——java的IO之字符流,字节流,转换流

------- android培训java培训、期待与您交流! ----------

前言:通过观看毕向东老师的java基础视频,查漏补缺,将一些自己掌握的还不牢固的知识写出来,希望和大家交流分享。

1.IO概述

1、相关概念:IO:即Input和Output的缩写。

2、作用和特点:

       1)IO流用来处理设备间的数据传输。设备包括内存和磁盘等.

       2)Java对数据的操作是通过流的方式。

       3)Java用于操作流的对象都在IO包中。

       4)流按操作数据分为两种:字节流和字符流。字符流是在字节流的基础之上,java的设计者为了方便对日常生活中的语言文字等操作而设计的.

       5)流按流向分为:输入流和输出流。

      注意:流只能操作数据,而不能操作文件。

3、IO流的常用基类:

       1)字节流的抽象基流:InputStream和OutputStream

       2)字符流的抽象基流:Reader和Writer

注:此四个类派生出来的子类名称都是以父类名作为子类名的后缀,以前缀为其功能;如InputStream子类FileInputStream;Reader子类FileReader

2.字符流

1、字符串是我们日常生活中最熟悉的。字符流的操作更贴近生活,更易理解。

       1)字符流中的对象融合了编码表。使用的是默认的编码,即当前系统的编码。

       2)字符流只用于处理文字数据,而字节流可以处理媒体数据。

       3)既然IO流是用于操作数据的,那么数据的最常见体现形式是文件。查看API,找到一个专门用于操作文件的Writer子类对象:FileWriter。后缀是父类名,前缀名是流对象的功能。该流对象一被初始化,就必须有被操作的文件存在。

2、字符流的读写

      1)写入字符流步骤

       a、创建一个FileWriter对象,该对象一被初始化,就必须要明确被操作的文件。且该目录下如果已有同名文件,则同名文件将被覆盖。其实该步就是在明确数据要存放的目的地。

       b、调用write(String s)方法,将字符串写入到流中。

       c、调用flush()方法,刷新该流的缓冲,将数据刷新到目的地中。

       d、调用close()方法,关闭流资源。但是关闭前会刷新一次内部的缓冲数据,并将数据刷新到目的地中。

     2)close()和flush()区别:

       flush()刷新后,流可以继续使用;

       而close()刷新后,将会关闭流,不可再写入字符流。

       注意:其实java自身不能写入数据,而是调用系统内部方式完成数据的书写,使用系统资源后,一定要关闭资源。

3、代码实例:

  1)FileWriter的基本操作.

示例1,写入文件

package file;

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo {
	public static void main(String[] args) throws IOException {
		/*
		 * 创建一个FileWriter对象,该对象必须要明确被操作的文件才能被初始化。
		 * 该文件会被创建到指定目录下,如果该目录下已经有同名的文件,将被覆盖。
		 * 该步是 要明确数据要存放的位置。
		 */
		FileWriter fw = new FileWriter("demo.txt");
		
		//调用write方法将字符串写入到流中,即内存中的特定区域
		fw.write("abcde");
		
		//刷新流对象中的缓冲中的数据,将数据刷到目的地中
		fw.flush();
		//继续写和刷新
		fw.write("songwenju");
		fw.flush();
		
		fw.write("111");
		//关闭流资源,释放所占的内存空间,在执行close之前会把流中的数据刷新到目的文件中。
		//一个流一旦关闭就不能再写了。
		fw.close();
	}
}

运行结果:


2)  文件的数据的续写是通过构造函数FileWriter(Strings,boolean append),在创建对象时,传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。(windows系统中的文件内换行用\r\n两个转义字符表示,在linux系统中只用\n表示换行)

示例2:文件续写

package file;

import java.io.FileWriter;
import java.io.IOException;

/**
 * 对已有的文件进行续写
 * @author songwenju
 *
 */
public class FileWriterDemo2 {
	public static void main(String[] args) throws IOException {
		//传递一个true参数表示不覆盖原有的文件,而是在文件的后面续写
		FileWriter fw = new FileWriter("demo.txt",true);
		fw.write("O(∩_∩)O\r\n谢谢");
		fw.close();
	}
}

运行结果:


3)由于在创建对象时,需要指定创建文件位置,如果指定的位置不存在,就会发生IOException异常,所以在整个步骤中,需要对IO异常进行try处理。

示例3:完整的IO异常处理

package file;

import java.io.FileWriter;

/**
 * 完整的IO异常处理
 * @author songwenju
 *
 */
public class IOException {
	public static void main(String[] args) {
		FileWriter fw = null;
		try {
			//初始化在里面
			fw = new FileWriter("demo.txt");
			fw.write("111");
		} catch (java.io.IOException e) {
			e.printStackTrace();
		}finally{
			//判断是否为空
			if (fw != null) {
				try {
					fw.close();
				} catch (java.io.IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

4)读字符流

         读取字符流步骤

        1)创建一个文件读取流对象,和指定名称的文件相关联。要保证该文件已经存在,若不存在,将会发生异常FileNotFoundException。

        2)调用读取流对象的read()方法。read():一次读一个字符,且会继续往下读。

             第一种方式:读取单个字符。第二种方式:通过字符数组进行读取。

        3)读取后要调用close方法将流资源关闭

 示例4:读字符流

package file;

import java.io.FileReader;
import java.io.IOException;

/**
 * 读字符流
 * @author songwenju
 *
 */
public class FileReaderDemo {
	public static void main(String[] args) throws IOException {
		FileReader fr = new FileReader("demo.txt");
		//调用读取流对象的read方法
		//read一次只读取一个字符,而且会主动往下读,一直到-1
		
		/*System.out.println("ch1 = "+(char)fr.read());
		System.out.println("ch2 = "+(char)fr.read());
		System.out.println("ch3 = "+(char)fr.read());
		System.out.println("ch4 = "+(char)fr.read());
		System.out.println("ch5 = "+(char)fr.read());
		System.out.println("ch6 = "+fr.read());*/
		int ch;
		
		/*while (true) {
			ch = fr.read();
			if (ch == -1) {
				break;
			}
			System.out.println((char)ch);
		}*/
		while ((ch = fr.read()) != -1) {
			System.out.println((char)ch);
		}
		fr.close();
	}
}

5)文件的复制

示例4:将D盘v5文件中的file.java文件拷贝到D盘v5的songwenju文件夹下。

package file;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 将D盘v5文件中的file.java文件拷贝到D盘v5的songwenju文件夹下
 * @author songwenju
 *	思路:先读取,然后再写入
 */
public class CopyFile {
	public static void main(String[] args) throws IOException {
		copy1();
		copy2();
		copy3();
	}
	public static void copy3(){
		FileReader fr = null;
		FileWriter fw = null;
		try {
			fr = new FileReader("D:/v5/File.java");
			fw = new FileWriter("D:/v5/songwenju/File3.java");
			char[] buf = new char[1024];
			int count;
			while((count = fr.read(buf)) != -1){
				fw.write(buf, 0, count);//这样会读多少写多少,fw.write(buf)会写入1024个字符。
			}
		} catch (IOException e) {
			throw new RuntimeException("流异常");
		}finally{
			try {
				if (fw != null) {
					fw.close();
				}
			} catch (IOException e2) {
				throw new RuntimeException("流异常");
			}
			
			try {
				if (fr != null) {
					fr.close();
				}
			} catch (Exception e2) {
				throw new RuntimeException("流异常");
			}
		}
	}
	/**
	 * 读一个字符写一个字符
	 * @throws IOException
	 */
	public static void copy2() throws IOException{
		FileReader fr = new FileReader("D:/v5/File.java");
		FileWriter fw = new FileWriter("D:/v5/songwenju/File2.java");
		int ch;
		while ((ch = fr.read()) != -1) {
			fw.write(ch);
		}
		fw.close();//必须要flush
		fr.close();
	}
	/**
	 * 自己写的多了一步拼接
	 * @throws IOException
	 */
	public static void copy1() throws IOException{
		FileReader fr = new FileReader("D:/v5/File.java");
		FileWriter fw = new FileWriter("D:/v5/songwenju/File.java");
		char [] buf = new char[1024];
		int count;
		StringBuffer sBuffer = new StringBuffer();
		while((count = fr.read(buf)) != -1){//读的时候要判断是否读到末尾,写的时候一次写完。
			//System.out.print(new String(buf,0,count));
			sBuffer.append(new String (buf,0,count));
		}
		fw.write(new String(sBuffer));
		fw.close();
		fr.close();
	}
}

4、字符流的缓冲区——BufferedReader和BufferedWriter

    1)缓冲区的出现:提高了流的读写效率,所以在缓冲区创建前,要先创建流对象。即先将流对象初始化到构造函数中。 

    2)缓冲技术原理:此对象中封装了数组,将数据存入,再一次性取出。

    3)写入流缓冲区BufferedWriter的步骤:

             a)创建一个字符写入流对象。

                 如:FileWriter fw=newFileWriter("buf.txt");

            b)为了提高字符写入流效率。加入缓冲技术。只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。

                 如: BufferedWriter bufw =new BufferedWriter(fw);

            c)调用write方法写入数据到指定文件

                 如:bufw.write("adfg");

           d)记住,只要用到缓冲区,就要记得刷新。(关闭流同样会刷新,但为了排除意外事故,保证数据存在,建议写入一次就刷新一次)

                 如:bufw.flush();

           e)其实关闭缓冲区,就是在关闭缓冲区中的流对象。

                如: bufw.close();

           f )小知识:BufferedWriter缓冲区中提供了一个跨平台的换行符:newLine();可以在不同操作系统上调用,用作数据换行。

              如:bufw.newLine();

      4)读取流缓冲区BufferedReader

            该缓冲区提供了一个一次读一行的方法readLine,方便于堆文本数据的获取,当返回null时表示读到文件末尾。

           readLine方法返回的时候,只返回回车符之前的数据内容。并不返回回车符。

      5)readLine方法原理:

          无论是读一行。或者读取多个字符。其实最终都是在在硬盘上一个一个读取。所以最终使用的还是read方法一次读一个的方法。

      6)使用缓冲区读出数据BufferReader的步骤:

             a)创建一个读取流对象和文件相关联

                  如: FileReader fr=newFileReader("buf.txt");

            b)为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲区对象的构造函数。

                 如: BufferedReader bufr=new BufferedReader(fr);

            c)调用该缓冲区提供的readLine方法一行一行读取,如果到达文件末尾,则返回null

                 如: String s=bufr.readLine();

            d)关闭流资源

                 如: bufr.close();

示例:通过缓冲区复制一个文本文件。

package file;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 通过缓冲区copy一个.java文件
 * @author songwenju
 *
 */
public class CopyFileByBuffer {
	public static void main(String[] args) {
		BufferedReader bufr = null;
		BufferedWriter bufw = null;
		try {
			//这里就是嵌套流了。
			bufr = new BufferedReader(new FileReader("D:/v5/File.java"));
			bufw = new BufferedWriter(new FileWriter("D:/v5/FileBuffer.java"));
			String line = null;
			while ((line = bufr.readLine())!=null) {
				bufw.write(line);
				//readLine包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null ,故加上newLine
				bufw.newLine();
				bufw.flush();
			}
		} catch (IOException e) {
			throw new RuntimeException("文件读写错误");
		}finally{
			try {
				if (bufw != null) {
					bufw.close();
				}
			} catch (IOException e2) {
				throw new RuntimeException("文件写关闭错误");
			}
			try {
				if (bufr != null) {
					bufr.close();
				}
			} catch (IOException e2) {
				throw new RuntimeException("文件读关闭错误");
			}
		}
	}
}
5.模拟BufferReader

原理:根据BufferedReader类中特有一行一行读取方法readLine()的原理,自定义一个类中包含相同功能的方法

步骤:

        a、初始化自定义的类,加入流对象。

        b、定义一个临时容器,原BufferedReader封装的是字符数组,此类中可定义一个StringBuilder的容器,最终可实现字符串的提取。

package file;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

class MyBufferReader extends Reader{//对每个Reader的子类都能增强
	private Reader r;//定义接收流的对象
	public MyBufferReader(Reader r) {
		this.r = r;
	}
	//自定义整行读取  
	public String myReadLine()throws IOException{
		//创建一个容器,用来存储一行的字符  
		StringBuilder sb = new StringBuilder();
		for (int ch = 0; (ch = r.read())!= -1;) {
			//如果遇到换行符,则跳过后面的内容
			if (ch == '\r') {
				continue;
			}
			//如果遇到回车符,表示该行读取完毕 
			if (ch == '\n') {
				return sb.toString();
			}else {
				sb.append((char)ch);//将该行的字符添加到容器  
			}
		}
		//如果读取结束,容器中还有字符,则返回元素
		if (sb.length() != 0) {
			return sb.toString();
		}
		return null;
	}
	@Override
	public int read(char[] cbuf, int off, int len) throws IOException {
		return r.read(cbuf, off, len);
	}

	@Override
	public void close() throws IOException {
		r.close();
	}
}
public class MyBufferReaderDemo{
	public static void main(String[] args) {
		MyBufferReader mReader = null;
		try {
			mReader = new MyBufferReader(new FileReader("demo.txt"));
			for (String line = null; (line = mReader.myReadLine())!= null;){
				System.out.println(line);
			}
		} catch (FileNotFoundException e) {
			throw new RuntimeException("文件找不到");
		} catch (IOException e) {
			throw new RuntimeException("IO异常");
		}finally{
			try {
				if (mReader != null) {
					mReader.close();
				}
			} catch (IOException e2) {
				throw new RuntimeException("流关闭异常");
			}
		}
	}
}

运行结果:(示自己的文件内容而定)

6.装饰设计模式

1)当想对已有对象进行功能增强时,可定义类:将已有对象传入,基于已有对象的功能,并提供加强功能,那么自定义的该类称之为装饰类。

2) 装饰类通常都会通过 构造方法接收被装饰的对象,如果直接改源代码会造成灾难性的后果,并基于被装饰的对象的功能,提供更强的功能。

3)装饰和继承的区别:

        1)装饰模式比继承要灵活。避免了继承体系的臃肿(有时候为了添加个别共同的功能每个类都要添加该功能的子类就造成了臃肿,

           不如抽取改方法用去装饰),且降低了类与类之间的关系。

        2)装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系。

        3)从继承结构转为组合结构。

注:在定义类的时候,不要以继承为主;可通过装饰设计模式进行增强类功能。灵活性较强,当装饰类中的功能不适合,可再使用被装饰类的功能。

代码示例:

package file;

/**
 * 装饰设计模式
 * @author songwenju
 *
 */
class Person{
	public void eat(){
		System.out.println("吃饭");
	}
}
class DecoratePerson{
	private Person p;
	public DecoratePerson(Person p) {
		this.p = p;
	}
	public void decorateEat(){
		System.out.println("开胃菜");
		p.eat();
		System.out.println("甜点");
	}
}
public class DecorateDemo {
	public static void main(String[] args) {
		Person person = new Person();
		DecoratePerson dPerson = new DecoratePerson(person);
		dPerson.decorateEat();
	}
}
7.LineNumberReader

   在BufferedReader中有个直接的子类LineNumberReader,其中有特有的方法获取和设置行号:

         setLineNumber();//设置初始行号

         getLineNumber();//获取行号

代码示例:
package file;

import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

/**
 * LineNumberReader练习
 * @author songwenju
 *
 */
public class LineNumberReaderDemo {
	public static void main(String[] args) throws IOException {
		//使用相对路径要加src
		FileReader fReader = new FileReader("src/file/FileListDemo.java");
		
		LineNumberReader lReader = new LineNumberReader(fReader);
		String line = null;
		//lReader.setLineNumber(100);
		while((line = lReader.readLine())!= null){
			System.out.println(lReader.getLineNumber()+"   "+line);
		}
		lReader.close();
	}
}
运行结果:

4.字节流

1.字节流和字符流的基本操作是相同的,但字节流还可以操作其他媒体文件。

2.由于媒体文件数据中都是以字节存储的,所以,字节流对象可直接对媒体文件的数据写入到文件中,而可以不用再进行刷流动作。

因为字节流操作的是字节,即数据的最小单位,不需要像字符流一样要进行转换为字节。所以可直接将字节数据写入到指定文件中。

3.InputStream   输入流(读)  OutputStream  输出流(写)

4.字节流基本操作代码示例:

package file;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 字节流的操作
 * @author songwenju
 *
 */
public class FileStream {
	public static void main(String[] args) throws IOException {
		//writeFile();
		//readFile_1();
		//readFile_2();
		readFile_3();
	}
	/**
	 * 以1024字节大小为块进行读取
	 * @throws IOException
	 */
	public static void readFile_3() throws IOException {
		InputStream  in = new FileInputStream("fos.txt");
		int num = in.available();//得到文件的大小,该方法慎用。如果文件比较大大于虚拟机的内存,会报错。
		//故第2种方法比较好。
		
		System.out.println(num);//3
		byte[] b = new byte[in.available()];
		in.read(b);
		System.out.println(new String (b,0,b.length));
		in.close();
	}
	/**
	 * 以1024字节大小为块进行读取
	 * @throws IOException
	 */
	public static void readFile_2() throws IOException {
		InputStream  in = new FileInputStream("fos.txt");
		byte [] b = new byte[1024];//1024的整数倍
		int len = 0;
		while ((len = in.read(b))!= -1) {
			System.out.println(new String(b,0,len));
		}
		in.close();
	}
	
	/**
	 * 一个一个字节的读,读出的数据是int类型转化为char
	 * @throws IOException
	 */
	public static void readFile_1() throws IOException {
		InputStream in = new FileInputStream("fos.txt");
		
		int b = 0;
		while ((b =  in.read())!= -1) {
			System.out.println((char)b);
			
		}
		in.close();
	}
	
	/**
	 * 写入内容
	 * @throws IOException
	 */
	public static void writeFile() throws IOException {
		OutputStream out = new FileOutputStream("fos.txt");
		//字符串转换为字节数组:"abcde".getBytes()
		//字符串转换为字符数组:"abcde".toCharArray()
		out.write("abc".getBytes());
		//字符流底层也是使用的是字节流.
		//字节流不需要缓冲,也就是不需要刷新,他是对数据最小单位操作。但还要关闭资源。
		out.close();
	}
}
5.复制一个图片代码示例:

package file;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 复制图片用字节流
 * 如果用字符流复制会出现乱码情况,而字节流不会,它复制的是01
 * @author songwenju
 *
 */
public class CopyPicture {
	public static void main(String[] args) throws IOException {
		copyFile();
	}
	
	/**
	 * 推荐使用的方法
	 * @throws IOException
	 */
	public static void copyFile() throws IOException{
		InputStream in = new FileInputStream("src/file/1.png");
		OutputStream out = new FileOutputStream("src/file/2.png");
		byte[] b = new byte[1024];
		int len = 0;
		while((len = in.read(b)) != -1){
			out.write(b, 0, len);
		}
		out.close();
		in.close();
		
	}
}
6.字节流缓冲区

        同样是提高了字节流的读写效率。

    1)读写特点:

        read():会将字节byte型值提升为int型值

        write():会将int型强转为byte型,即保留二进制数的最后八位。

   2)原理:将数据拷贝一部分,读取一部分,循环,直到数据全部读取完毕。

        a)先从数据中抓取固定数组长度的字节,存入定义的数组中,再通过然后再通过read()方法读取数组中的元素,存入缓冲区。

        b)循环这个动作,直到最后取出一组数据存入数组,可能数组并未填满,同样也取出包含的元素。

        c)每次取出的时候,都有一个指针在移动,取到数组结尾就自动回到数组头部,这样指针在自增。

        d)取出的时候,数组中的元素在减少,取出一个,就减少一个,直到减到0即元素取完。

        e)当文件中的全部数据都被读取出时,read()方法就返回-1。

   3)自定义读取字节流缓冲区

        需求:根据字节流缓冲区的原理,自定义一个字节流缓冲区。

       注意:

        1、字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。

       因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。

       所以,为了避免这种情况将读到的字节进行int类型的提升。并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。而在写入数据时,只写该int类型数据的最低8位。

        2、byte类型的-1提升为int类型时还是-1。原因:因为在bit8个1前面补的全是1导致的。如果在bit8个1前面补0,即可以保留原字节数据不变,又可以避免-1的出现。这时将byte型数据&0xff即255即可。

代码示例:自定义BufferInputStream

package file;

import java.io.IOException;
import java.io.InputStream;

/**
 * 自定义bufferInputStream
 * @author songwenju
 *
 */
public class MyBufferInputStream {
	private InputStream in;
	private byte[] b = new byte[1024];
	private int count = 0,pos = 0;
	public MyBufferInputStream(InputStream in) {
		this.in = in;
	}
	
	//自定义读方法,一次读一个字节  
	public int myRead() throws IOException{
		//通过in对象读取硬盘上数据,并存储b中。  
        //存储在数组中的数据被读取完,再通过in对象从硬盘上读取数据  
		if (count == 0) {
			count = in.read(b);
			if (count < 0) {//文件数据全部被读取出来了  
				return -1;
			}
			pos = 0;//初始化指针  
			byte by = b[pos];
			count--;//每被读一个字节,表示数组中的字节数少一个  
			pos++;//指针加1  
			//返回的byte类型提升为int类型,字节数增加,且高24位被补1,原字节数据改变。  
			//通过与上255,主动将byte类型提升为int类型,将高24位补0,原字节数据不变。  
            //而在输出字节流写入数据时,只写该int类型数据的最低8位。 
			return by&0xff;
		}else if (count > 0) {//如果数组中的数据没被读取完,则继续读取 
			byte by = b[pos];
			count--;
			pos++;
			return by&0xff;
		}
		return -1;
	}
	 //自定义关闭资源方法  
	public void close()throws IOException{
		in.close();
	}
}

该类的使用:

package file;

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyMP3 {
	public static void main(String[] args) throws IOException {
		long start = System.currentTimeMillis();
		copyFile();
		long end = System.currentTimeMillis();
		System.out.println("一共用了"+(end - start)+"毫秒");
		
	}
	public static void copyFile() throws IOException{
		MyBufferInputStream bin = new MyBufferInputStream(new FileInputStream("src/file/0.mp3"));
		BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream("src/file/2.mp3"));
		
		int b = 0;
		while((b = bin.myRead())!= -1){
			bout.write(b);
		}
		bout.close();
		bin.close();
	}
}
运行结果:

5.转换流

1.键盘录入

        1)标准输入输出流

              System.in:对应的标准输入设备,键盘。

              Sytem.out:对应的是标准的输出设备,控制台。

              System.in的类型是InputStream.  API中:public static final InputStream in

              System.out的类型是PrintStream是OutputStream的子类FilterOutputStream的子类。

代码示例:

package file;

import java.io.IOException;
import java.io.InputStream;

/**
 * 读取键盘录入
 * @author songwenju
 *
 */
public class ReadIn {
	public static void main(String[] args) throws IOException {
		InputStream in = System.in;
		
		// \r的ASCII码是: 13
		System.out.println("\\r的ASCII码是: "+('\r'+0));
		//\n的ASCII码是: 10
		System.out.println("\\n的ASCII码是: "+('\n'+0));
		
		int b = in.read();
		int b1 = in.read();
		int b2 = in.read();
		System.out.println(b);//输入abc,输出97,只读一个字节
		System.out.println(b1);//输入abc,输出97,98,读两个字节	
		System.out.println(b2);//输入a,输出97,13,10,读两个字节,可知在Windows中换行是\r\n	
	}
}

2.整行录入

当使用输入流进行键盘录入时,只能一个字节一个字节进行录入。为了提高效率,可以自定义一个数组将一行字节进行存储。

自定义读入一行:

package file;

import java.io.IOException;
import java.io.InputStream;

/**
 * 自己写的读取一行数据
 * @author songwenju
 *
 */
public class ReadLine {
	public static void main(String[] args) throws IOException {
		InputStream in = System.in;
		StringBuilder sb = new StringBuilder();
		//就是上面写的readLine方法
		while (true) {
			int ch = in.read();
			if (ch == '\r') {
				continue;
			}
			if (ch == '\n') {
				String s = sb.toString();
				if ("over".equals(s)) {
					break;
				}
				System.out.println(s.toUpperCase());
				sb.delete(0, sb.length());//清空内容
			}else {
				sb.append((char)ch);
			}
		}
	}
}

当一行录入完毕,再将一行数据进行显示。这种正行录入的方式,和字符流读一行数据的原理是一样的。也就是readLine方法。

那么能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?

     readLine方法是字符流BufferedReader类中方法。而键盘录入的read方法是字节流InputStream的方法。

那么能不能将字节流转成字符流再使用字符流缓冲区的readLine方法呢?

      这就需要用到转换流了。

3.转换流

     1) 转换流的由来:字符流与字节流之间的桥梁。方便了字符流与字节流之间的操作。转换流的应用:字节流中的数据都是字符时,转成字符流操作更高效。

     2)InputStreamReader将字节流通向字符流的步骤:

             a)获取键盘录入对象。

                  InputStream in=System.in;

             b)将字节流对象转成字符流对象,使用转换流。

                 InputStreamReader isr=new InputStreamReader(in);

             c)为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader

                 BufferedReaderbr=new BufferedReader(isr);

                //键盘录入最常见写法

                 BufferedReader  in=new BufferedReader(new InputStreamReader(System.in));

     3)OutputStreamWriter字符流通向字节流

           字符通向字节:录入的是字符,存到硬盘上的是字节。步骤和InputStreamReader转换流一样。

          代码示例:

package file;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
 * 将键盘录入的数据,显示在文件,当输入over时,表示结束 
 * @author songwenju
 *
 */
public class TransferStream {
	public static void main(String[] args) throws IOException {
		/*//获取键盘录入对象。  
		InputStream in = System.in;
		//将字节流对象转成字符流对象,使用转换流。
		InputStreamReader isr = new InputStreamReader(in);
		//为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader  
		BufferedReader bufr = new BufferedReader(isr);*/
		
		//以上三句话变一句话
		BufferedReader bufr = new BufferedReader(
				new InputStreamReader(System.in));
		
		
		//将字符流转换为字节流OutputStreamWriter
		
		/*OutputStream out = System.out;
		OutputStreamWriter osw = new OutputStreamWriter(out);
		BufferedWriter bufw = new BufferedWriter(osw);
		*/
		//以上三句变一句,这一句是键盘录入的最常见写法
		BufferedWriter bufw = new BufferedWriter(
				new OutputStreamWriter(new FileOutputStream("os.txt")));
		
		String line = null;
		while ((line = bufr.readLine())!= null) {
			if ("over".equals(line)) {
				break;
			}
			//有了输出后就不用这个了,直接用osw
			//System.out.println(line.toUpperCase());
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush();
		}
		bufw.close();
		bufr.close();
	}
}
运行结果:


------- android培训java培训、期待与您交流! ----------

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值