14:IO之字符字节流
字节流:InputStream OutputStream 字节流: FileInputStreamFileOutputStreamBufferedInputStreamBufferedOutputStream字符流:Writer ReaderFileReaderFileWriterBufferedReaderBufferedWriter
第一 IO流概述
一、概述:
IO流是来处理设备间的数据传输
1、特点:
1)流操作按照数据可分为字节流(处理所有的数据)和字符流(处理文字,其中包含编码表,可以指定编码表防止了编码表不同而产生乱码的现象)
2)按照流向分可以分为输出流和输入流。
字节流的抽象基类:InputStream(读)、OutputStream(写)
字符流的抽象基类:Reader(读)、Writer(写)
注:此四个类派生出来的子类名称都是以父类名作为子类名的后缀,以前缀为其功能;
第二 字符流
一、简述:
1、字符流中的对象融合了编码表。使用的是默认的编码,即当前系统的编码。
2、字符流只用于处理文字数据,而字节流可以任何数据。
3、既然IO流是用于操作数据的,那么数据的最常见体现形式是文件。专门用于操作文件的子类对象:FileWriter、FileReader
二、写入字符流
- 数据的续写是通过构造函数 FileWriter(String s,boolean append),根据给定文件名及指示是否附加写入数据的boolean值来构造FileWriter对象。为true时就是续写,为false就是不续写。
- 调用write()方法,将字符串写入到流中。这里他本身没有特定的写方法都是继承自父类的方法有写单个字符:
write(int c),写入字符数组:
write(char[] cbuf)这里的数组一般定义成1024的整数倍,不宜过大,过大容易造成内存溢出。写入字符数组的某一部分:write(char[] cbuf, int off, int len),写入字符串:
write(String str),写入字符串的某一部分:write(String str, int off, int len)
- *
- * 需求:在硬盘上,创建一个文件并写入一些文字数据。
- * 找到一个专门用于操作文件的Writer子类对象。FileWriter。 后缀名是父类名。 前缀名是该流对象的功能。
- */
- public class FileWriterDemo {
- public static void main(String[] args) {
- method();//写内容
- method2();//续写内容
- }
- /*
- * 写数据
- */
- public static void method(){
- FileWriter fw = null;
- try {
- //创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
- //该文件会被存放在指定的目录下,如果该文件已经存在,会被覆盖
- //其实该步就是在明确数据要存放的目的地。
- fw = new FileWriter("testwrite.txt");// C:\\testwrite.txt
- //调用write方法,将字符串写入到流中
- fw.write("asdsadafsd");
- //刷新流对象中的缓冲中的数据。
- //将数据刷到目的地中。
- // fw.flush();
- //关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
- //将数据刷到目的地中。
- //和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
- // fw.close();
- } catch (IOException e) {
- e.printStackTrace();
- }finally{
- try {
- if(fw != null)
- fw.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- /*
- * 在文件原有内容的基础上续写内容
- */
- public static void method2(){
- FileWriter fw = null;
- try {
- fw = new FileWriter("testwrite.txt", true);
- fw.write("\r\nnihao\r\nxiexie");//\r\n是换行符\n是linux下的换行
- } catch (IOException e) {
- e.printStackTrace();
- }finally{
- if(fw != null){
- try {
- fw.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
三、读取字符流
- 创建一个文件读取流对象,和指定名称的文件相关联。要保证该文件已经存在,若不存在,将会发生异常FileNotFoundException。
- 调用读取流对象的read()方法。read():一次读一个字符,且会继续往下读。(方法1)
read()读取单个字符。
其实都是按照每次只读取一个字符的方式读取的,只是读到数组中会把读取到的数据存放在数组中,起到一个临时缓存的作用,提高了读取效率。read(char[] cbuf)将字符读入数组。(方法2)
演示1:
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt");
int ch = 0;
while((ch=fr.read())!=-1){// abcde读5次
System.out.println((char)ch);
fr.close();
}
演示2:
public class FileReaderDemo2 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt");
/*
* 使用read(char[])读取文本文件数据。
*
* 先创建字符数组。
*/
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf))!=-1){ // abcde读1次,提高效率,是一个数组一个数组的读
System.out.println(new String(buf,0,len));
}
/*
int num = fr.read(buf);//将读取到的字符存储到数组中。读到几个几个变成数组
System.out.println(num+":"+new String(buf,0,num));
int num1 = fr.read(buf);//将读取到的字符存储到数组中。
System.out.println(num1+":"+new String(buf,0,num1));
int num2 = fr.read(buf);//将读取到的字符存储到数组中。
System.out.println(num2+":"+new String(buf));
*/
- }
四、文件的拷贝:
原理:其实就是将磁盘下的文件数据读取出来,然后写入磁盘的一个文件中
步骤:
1、在硬盘上创建一个文件,用于存储读取出来的文件数据
2、定义读取流和文件关联
3、通过不断读写完成数据存储
方式一:读取一个字符,存入一个字符
方式二:先将读取的数据存入到内存中,再将存入的字符取出写入硬盘
4、关闭流资源:输入流资源和输出流资源。
方法1:
/*
* 思路:
* 1,需要读取源,
* 2,将读到的源数据写入到目的地。
* 3,既然是操作文本数据,使用字符流。
*
*/
public class CopyTextTest {
public static void main(String[] args) throws IOException {
//1,读取一个已有的文本文件,使用字符读取流和文件相关联。
FileReader fr = new FileReader("IO流_2.txt");
//2,创建一个目的,用于存储读到数据。
FileWriter fw = new FileWriter("copytext_1.txt");
//3,频繁的读写操作。
int ch = 0;
while((ch=fr.read())!=-1){
fw.write(ch);
}
//4,关闭流资源。先关写再关读
fw.close();
fr.close();
}
}
方法2:
public class CopyTextTest_2 {
private static final int BUFFER_SIZE = 1024;
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("IO流_2.txt");
fw = new FileWriter("copytest_2.txt");
//创建一个临时容器,用于缓存读取到的字符。
char[] buf = new char[BUFFER_SIZE];//这就是缓冲区。
//定义一个变量记录读取到的字符数,(其实就是往数组里装的字符个数 )
int len = 0;
while((len=fr.read(buf))!=-1){
fw.write(buf, 0, len);
}
} catch (Exception e) {
// System.out.println("读写失败");
throw new RuntimeException("读写失败");
}finally{
if(fw!=null)
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
if(fr!=null)
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
第三 字符缓冲区
/
* 缓冲区的出现就是为了提高操作流的效率
* 所以在创建缓冲区之前必须要先有流对象
*
* 缓冲区提供了一个跨平台的换行符 new Line();
*/
public class BufferedWriterDemo {
public static void main(String[] args) {
method();
}
public static void method() {
// 创建一个字符写入流对象
FileWriter fw = null;
BufferedWriter bfw = null;
try {
fw = new FileWriter("buf.txt");
// 为了提高字符写入流效率。加入了缓冲技术。其实缓冲区就是封装了数组,不用自己定义数组,用起来更方便
// 只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
bfw = new BufferedWriter(fw);
for (int x = 0; x < 10; x++) {
bfw.write("abcds" + x);
bfw.newLine();// 换行在windows中相当于\r\n,在linux中相当于\n
}
// 记住,只要用到缓冲区,就要记得刷新。
// bufw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bfw.close();// 关闭缓冲区就是在关闭缓冲区中的流对象,关闭前刷新
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
//使用缓冲区的写入方法将数据先写入到缓冲区中。
// bufw.write("abcdefq"+LINE_SEPARATOR+"hahahha");
// bufw.write("xixiixii");
// bufw.newLine(); 行分隔,就不需要LINE_SEPARATOR,不过只在这里有效
// bufw.write("heheheheh");
该缓冲区提供了一个一次读一行的方法readLine(),方便与对文本数据的获取,当返回null时,表示读到文件末尾。
readLine()方法返回的时只返回回车符之前的数据内容,并不返回回车符,即读取的内容中不包含任何行终止符(回车符和换行符)。
--->readLine()方法原理:无论是读一行,或读取多个字符,其实最终都是在硬盘上一个一个读取。所以最终使用的还是read方法一次读一个
public class BufferedReaderDemo {
public static void main(String[] args) {
method();
}
public static void method(){
//创建一个读取流对象
FileReader fr = null;
BufferedReader bfr = null;
try {
fr = new FileReader("buf.txt");
//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
bfr = new BufferedReader(fr);
// char[] buf = new char[1024];
// bfr.read(buf);
// int len = 0;
// while((len = bfr.read(buf)) != -1){
// System.out.println(new String(buf,0,len));
// }
String line = null;
while((line = bfr.readLine()) != null){
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
bfr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class CopyTextByBufTest {
//
不处理异常,抛出去public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("buf.txt");
BufferedReader bufr = new BufferedReader(fr);
FileWriter fw = new FileWriter("buf_copy.txt");
BufferedWriter bufw = new BufferedWriter(fw);
String line = null;
while ((line = bufr.readLine()) != null) {
bufw.write(line);
bufw.newLine();
bufw.flush();
}
/*
* int ch = 0;
*
* while((ch=bufr.read())!=-1){
*
* bufw.write(ch); }
*/
bufw.close();
bufr.close();
}
}
public class CopyByBuffer {
public static void main(String[] args) {
copyByBuf();
}
public static void copyByBuf() {
FileWriter fw = null;
FileReader fr = null;
BufferedWriter bfw = null;
BufferedReader bfr = null;
try {
fw = new FileWriter("C:\\buffertest.txt");//创建写文件对象
fr = new FileReader("buffertest.txt");//创建读文件对象
bfw = new BufferedWriter(fw);//使用缓冲区关联读写对象
bfr = new BufferedReader(fr);
String line = null;
while ((line = bfr.readLine()) != null) {//通过读一行的方式提高效率
bfw.write(line);
bfw.newLine();//换行,夸平台
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bfw != null) {
try {
bfw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bfr != null) {
try {
bfr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class MyBufferedReader extends Reader {
private Reader r;
//定义一个数组作为缓冲区。
private char[] buf = new char[1024];
//定义一个指针用于操作这个数组中的元素。当操作到最后一个元素后,指针应该归零。
private int pos = 0;
//定义一个计数器用于记录缓冲区中的数据个数。 当该数据减到0,就从源中继续获取数据到缓冲区中。
private int count = 0;
MyBufferedReader(Reader r){
this.r = r;
}
/**
* 该方法从缓冲区中一次取一个字符。
* @return
* @throws IOException
*/
/*
public int myRead() throws IOException{
//从源中获取一批数据到缓冲区中。需要先做判断,只有计数器为0时,才需要从源中获取数据。
if(count==0){
count = r.read(buf); //这是在底层
if(count<0)//没有了
return -1;
//每次获取数据到缓冲区后,角标归零(第一个read,底层)创建了一个数组。
pos = 0;
char ch = buf[pos];
// 然后调用一次(第二个)read,返回一个a,再调用返回b,角标取一个,count减一个
pos++;
count--;
return ch;
}
else if(count>0){//第二次调用的时候count就不为0了, 不需要count = r.read(buf)这一步了
char ch = buf[pos];
pos++;
count--;
return ch;
}*/
优化后
public int myRead() throws IOException{
if(count==0){
count = r.read(buf);
pos = 0;
}
if(count<0)
return -1;
char ch = buf[pos++];
count--;
return ch;
}
public String myReadLine() throws IOException{
// 定义一个临时容器,原BufferedReader封装的是字符数组,这里定义StringBuilder演示原理
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch = myRead())!=-1){
if(ch=='\r') //如是'\r'继续往下读
continue;
if(ch=='\n') //读到'\n'就停止读,然后将这些数据返回
return sb.toString();
//将从缓冲区中读到的字符,存储到缓存行数据的缓冲区中。
sb.append((char)ch);
}
if(sb.length()!=0) //最后没有空格,说明有东西,返回,
//这里是防止最后一行没有回车符的情况
return sb.toString();
return null;
}
public void myClose() throws IOException {
r.close();
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
return 0;
}
@Override
public void close() throws IOException {
}
}
运行 ReadLine
public class MyBufferedReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("buf.txt");
MyBufferedReader bufr = new MyBufferedReader(fr);
String line = null;
while((line=bufr.myReadLine())!=null){
System.out.println(line);
}
bufr.myClose();
Collections.reverseOrder();
HashMap map = null;
map.values();
}
}
在BufferedReader中有个直接的子类LineNumberReader,其中有特有的方法获取和设置行号:
setLineNumber()和getLineNumber()
public class LineNumberReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("IO流_2.txt");
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
lnr.setLineNumber(100);// 默认是0
while ((line = lnr.readLine()) != null) {
System.out.println(lnr.getLineNumber() + ":" + line);
}
lnr.close();
}
}
第四 装饰设计模式
class Buffer {
Buffer(TextWriter w) // 要缓冲谁就加入进来
{
}
Buffer(MediaWirter w) // 要缓冲谁就加入进来
{
}
} // 但是这样做,来新对象还得加入,比较麻烦
// 都能写入,为了名字有意义,写成BufferWriter
class BufferWriter extends Writer {
BufferWriter(Writer w) {
}
}
第五 字节流
一、概述:
1、字节流和字符流的原理是相似的,而字符流是基于字节流的,字节流可以操作如媒体等其他数据,如媒体(MP3,图片,视频)等
2、由于媒体数据中都是以字节存储的,所以,字节流对象可直接对媒体进行操作,而不用再进行刷流动作。
3、InputStream ---> 输入流(读) OutputStream ---> 输出流(写)
4、为何不用进行刷流动作:因为字节流操作的是字节,即数据的最小单位,不需要像字符流一样要进行转换为字节。可直接将字节写入到指定文件中,但是需要在写代码的时候,如果有字符串,要将字符串转为字节数组再进行操作。
5、FileInputStream特有方法:int available() ---> 返回数据字节的长度,包含终止符
在定义字节数组长度的时候,可以用到这个方法:byte[] = new byte[fos.available()] (fos为字节流对象)但是,对于这个方法要慎用,如果字节过大,超过jvm所承受的大小(一般内存为64M),就会内存溢出。
/
* 字节流操作
* InputStream OutputStream
*
*/
public class FileStreamDemo {
public static void main(String[] args) {
// writeFile();
// readFile_1();
// readFile_2();
readFile_3();
}
/*
* 对字节流读操作的第一种方式 通过read()方法读取一个字节
*/
public static void readFile_1() {
FileInputStream fis = null;// 定义字节输入流
try {
fis = new FileInputStream("fos.txt");// 指定输入流和文件关联
int ch = 0;
while ((ch = fis.read()) != -1) {// 读取操作
System.out.println((char) ch);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null)// 判空,提高程序的健壮性
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 对字节流读操作的第二种方式 通过read(byte[])方法读取字节数组
*/
public static void readFile_2() {
FileInputStream fis = null;
try {
fis = new FileInputStream("fos.txt");
byte[] byf = new byte[1024];
int len = 0;
while ((len = fis.read(byf)) != -1) {
System.out.println(new String(byf, 0, len));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 对字节流读操作的第三种方式 通过字节流的available()方法获取到文件大小,定义一个大小刚刚好的数组,无需循环 但是,这种方式操作较大数据时容易内存溢出,所以要慎用 首选的还是定义1024的整数倍数组
*/
public static void readFile_3() {
FileInputStream fis = null;
try {
fis = new FileInputStream("fos.txt");
// 通过这样的方式定义一个刚刚好的数组
// 这种方法慎用,如果文件不大,可以用这个方法
byte[] byf = new byte[fis.available()];// fis.available()获取文件大小
fis.read(byf);
System.out.println(new String(byf));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 对字节流进行写操作
*/
public static void writeFile() {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("fos.txt");//定义字节写出流和文件关联
fos.write("abcds".getBytes());// str.getBytes()将String转化成字节数组
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null)
try {
fos.close();// 因为字节流没有用到缓冲区,所以不需要刷新,但必须关闭资源
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
思路:
1、用字节流读取流对象和媒体文件相关联
2、用字节写入流对象,创建一个媒体文件,用于存储获取到的媒体文件数据
3、通过循环读写,完成数据的存储
4、关闭资源
* 通过字节流拷贝图片
*/
public class CopyPicture {
public static void main(String[] args) {
copyPic();
}
public static void copyPic() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("1.jpg");
fos = new FileOutputStream("C:\\1.jpg");
byte[] byf = new byte[1024];
int len = 0;
while ((len = fis.read(byf)) != -1) {// 将数据读取到数组中
fos.write(byf, 0, len);// 写入数组中的有效数据
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 有多个流不能一起关闭,要分别关闭
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
// 千万不要用,效率没有!
public static void copy_4() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
FileOutputStream fos = new FileOutputStream("c:\\4.mp3");
int ch = 0;
while((ch =fis.read())!=-1){
fos.write(ch);
}
fos.close();
fis.close();
}
//不建议。
public static void copy_3() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
FileOutputStream fos = new FileOutputStream("c:\\3.mp3");
byte[] buf = new byte[fis.available()];
fis.read(buf);
fos.write(buf);
fos.close();
fis.close();
}
//提高效率
public static void copy_2() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
BufferedInputStream bufis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("c:\\2.mp3");
BufferedOutputStream bufos = new BufferedOutputStream(fos);
int ch = 0;
while((ch=bufis.read())!=-1){
bufos.write(ch);
}
bufos.close();
bufis.close();
}
1、缓冲区的出现无非就是提高了流的读写效率,当然也就是因为这样,所以缓冲区的使用频率也是相当高的,所以要做必要性的掌握。
2、字节流缓冲区读写的特点:
这里没有什么特殊的读写方法,就是read()读一个字节,read(byte[])读数组的方法。写
write(int b)写一个自己,write(byte[])写数组的方法。
原理:将数据拷贝一部分,读取一部分,循环,直到数据全部读取完毕。
1)先从数据中抓取固定数组长度的字节,存入定义的数组中,再通过然后再通过read()方法读取数组中的元素,存入缓冲区
2)循环这个动作,知道最后取出一组数据存入数组,可能数组并未填满,同样也取出包含的元素
3)每次取出的时候,都有一个指针在移动,取到数组结尾就自动回到数组头部,这样指针在自增
4)取出的时候,数组中的元素再减少,取出一个,就减少一个,直到减到0即数组取完
5)到了文件的结尾处,存入最后一组数据,当取完数组中的元素,就会减少到0,这是全部数据就取完了
* 自定义字节流缓冲区
*/
public class MyBufferedInputStream {
private InputStream in;
private byte[] buf = new byte[1024];
private int pos;// 定义数组的指针
private int count;// 定义计数器
MyBufferedInputStream(InputStream in) {
this.in = in;
}
// 一次读一个字节,从缓冲区(数组)中取得
public int myRead() throws IOException {
// 通过in对象读取数据并存放在buf数组中
if (count == 0) {
count = in.read(buf);
if (count < 0) {
return -1;
}
pos = 0;
byte b = buf[pos];
count--;
pos++;
return b & 255;// &255是因为存放的是二进制,也就是可能前八位是11111111,提升为int还是-1,就直接return了,
// &255就是让前面补0
/*
* 11111111 11111111 11111111 11111111
* &00000000 00000000 00000000 11111111
* ------------------------------------
* 00000000 00000000 00000000 11111111
*/
}else if(count>0){
byte b = buf[pos];
count--;
pos++;
return b&255;//&0xff
}
return -1;
}
public void myClose() throws IOException{
in.close();
}
}
当byte中的八位全为1的时候是byte的-1,提升为int类型,就变为int型的-1,为-1时程序就停止循环了,read循环条件就结束了,变为-1的原因是由于在提升时,将byte的八位前都补的是1,即32位的数都是1,即为int型的-1了。如何保证提升后的最后八位仍为1呢?就需要将前24位补0,就可以保留原字节数据不变,又可以避免转为int型出现-1的情况;
那么要如何做呢?
这就需要将提升为int的数据和前24位为0,后八位仍为原字节数据的这个值做与运算。即和255做与运算即可。说到了这里应该也明白了为什么Read方法返回值为int类型了。
第六 转换流
InputStreamReader 是字节流通向字符流的桥梁
OutputStreamWriter 是字符流通向字节流的桥梁
- //获取键盘录入对象
InputStream in = System.in;
//将字节流对象转换成字符流对象
InputStreamReader isr = new InputStreamReader(in);
//将字符流对象用缓冲技术高效处理
BufferedReader bufr = new BufferedReader(isr);
// 键盘录入最常见的写法
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
// 操作输出
// 获取输出流
OutputStream out = System.out;
//将字符流转换成字节流,OutputStreamWriter字符流通向字节流的桥梁
OutputStreamWriter osw = new OutputStreamWriter(out);
BufferedWriter bfw = new BufferedWriter(osw);//高效缓冲区
* 获取键盘录入
public class ReadIn {
public static void main(String[] args) {
// method_1();
// method_2();
InputStreamReaderDemo();
}
/*
* 获取键盘录入
*/
public static void method_1() {
InputStream in = System.in;// 定义输入流与键盘输入流相关联
int ch = 0;
try {
while ((ch = in.read()) != -1) {
System.out.println(ch);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* 需求:通过键盘录入数据。 当录入一行数据后,就将该行数据进行打印。 如果录入的数据是over,那么停止录入。
* 1,因为键盘录入只读取一个字节,要判断是否是over,需要将读取到的字节拼成字符串。
* 2,那就需要一个容器。StringBuilder.
* 3,在用户回车之前将录入的数据变成字符串判断即可。
*/
public static void method_2() {
InputStream in = System.in;
StringBuilder sb = new StringBuilder();// 定义一个临时容器
while (true) {
int ch = 0;
try {
ch = in.read();
if (ch == '\r')// windows中换行符为\r\n
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); //将读取到的字节存储到StringBuilder中。
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// **************************************************************************
/*
* 通过上面录入一行数据,发现其方法类似于readLine方法 但是readLine方法是字符流缓冲区的方法,所以需要把字节流转换成字符流进行操作
* 需要用到InputStreamReader方法进行转换,InputStreamReader字节通向字符的桥梁
*
* 转换流
*/
public static void InputStreamReaderDemo() {
BufferedReader bufr = null;
try {
// 源为文件
bufr = new BufferedReader(new InputStreamReader(
new FileInputStream("buf.txt")));
} catch (FileNotFoundException e2) {
e2.printStackTrace();
}
// 操作输出
// 目的地是控制台
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(
System.out));
// 目的地是文件
// BufferedWriter bfw = null;
// try {
// bfw = new BufferedWriter(new OutputStreamWriter(new
// FileOutputStream("out.txt")));
// } catch (FileNotFoundException e1) {
// e1.printStackTrace();
// }
String line = null;
try {
while ((line = bufr.readLine()) != null) {
if ("over".equals(line)) {
break;
}
bfw.write(line.toUpperCase());
bfw.newLine();// 换行
bfw.flush();// 数据存放在缓冲区,所以需要刷新
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
不处理异常
public class TransStreamDemo2 {
public static void main(String[] args) throws IOException {
/*
* 1,需求:将键盘录入的数据写入到一个文件中。
*
* 2,需求:将一个文本文件内容显示在控制台上。
*
* 3,需求:将一个文件文件中的内容复制到的另一个文件中。
*/
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt")));
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase()); //变成大写
bufw.newLine();
bufw.flush();
}
}
}
第七 流的操作规律
public static void writeText_2() throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
"gbk_3.txt"), "GBK");
// OutputStreamWriter osw = new OutputStreamWriter(new
// FileOutputStream("gbk_3.txt"),"GBK");
// FileWriter fw = new FileWriter("gbk_1.txt");
/*
* 这两句代码的功能是等同的。 FileWriter:其实就是转换流指定了本机默认码表的体现。而且这个转换流的子类对象,可以方便操作文本文件。
* 简单说:操作文件的字节流+本机默认的编码表。 这是按照默认码表来操作文件的便捷类。
*
* 如果操作文本文件需要明确具体的编码。FileWriter就不行了。必须用转换流
*/
osw.write("你好");
osw.close();
}
public static void writeText_3() throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
"u8_1.txt"), "UTF-8");
osw.write("你好");
osw.close();
}
public static void readText_1() throws IOException {
FileReader fr = new FileReader("gbk_1.txt");
char[] buf = new char[10];
int len = fr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
fr.close();
}
//用utf-8读默认的编码文件
public static void readText_2() throws IOException, FileNotFoundException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk_1.txt"),"utf-8");
char[] buf = new char[10];
int len = isr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
isr.close();
}
}
}