System 类
System类中的方法和属性都是静态的,out 标准输出,默认的是控制台,in 是标准输入,默认的是键盘。
public class Runtime extends Object
每个 Java 应用程序都有一个 Runtime
类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime
方法获取当前运行时。
应用程序不能创建自己的 Runtime 类实例。
Runtime 不能创建对象但是没有静态方法,通过某个静态方法提供一个对象并且能返回本类的类型的静态方法。
static Runtime | getRuntime() 返回与当前 Java 应用程序相关的运行时对象。 |
从这个特点看出该类使用了单类设计模式,保证了对象的唯一性。
package SystemDemo;
public class RuntimeDemo {
public static void main(String[] args) throws Exception
{
Runtime r = Runtime.getRuntime();
Process p = r.exec("notepad.exe ");
}
}
输出结果:
打开了一个记事本文件
property:
property 是一个map类的集合其中记载了系统的属性等相关信息。我们可以使用getProperties 的方法调用其中的系统信息。
public class SystemDemo {
public static void main(String[] args) {
Properties prop = System.getProperties();
//因为properties是Hashtable 的子类也就是Map集合的一个子类对象。那么可以通过map的方法得到该集合的元素。
//该集合中存储的都是字符串,没有泛型的定义。
String os = System.getProperty("os.name");
sop(os);
String v = System.getProperty("haha");
sop(v);
//property中的所有值打印
// for(Object obj :prop.keySet())
// {
// String value = (String)prop.get(obj);
// sop(obj+"::"+value);
// }
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
输出结果是:
Windows 7
null
我们除了可以打印某种相关的系统信息外,还能添加系统信息。
Date 类:
一个时间类,可以操作和时间相关的信息
package SystemDemo;
import java.util.*;
import java.text.*;
public class DateDemo {
public static void main(String[] args) {
Date d = new Date();
System.out.println(d);
//将模式封装到SimpleDateformat对象中
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日E hh:mm:ss");
//调用format方法让模式格式化指定Date对象
String time = sdf.format(d);
System.out.println("time = "+time);
}
}
输出结果:
Sun Dec 07 13:52:00 CST 2014
time = 2014年12月07日 星期日 01:52:00
单纯打印Date 的一个实例就给除了,星期 月 日 小时:分钟:秒 CST 年。 这样的时间信息,就是你输出的瞬间的时间
如果调用SimpleDateFormat可以自定义时间输出格式在后边 加上一个模式就可以指定的模式输出了。
IO 常用基类
字节流的抽象基类
ImputStream,OutputStream
字符流的抽象基类
Reader,Writer
流操作的基本规律:
流对象有很多,使用的时候一定要知道用哪个,可以通过明确判定来完成
1 明确源和目的
源:输入流,InputStream 和 Reader
目的:输出流,OutputStream 和 Writer
2 操作的数据是否是纯文本
是纯文本:用字符流
不是出文本:用字节流
3 当体系明确后,再明确要使用哪个具体的对象。
通过设备来进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
需求1 将一个文本文件中的数据存储到另一个文件中。复制文件
因为是源头:InputStream Reader
如果是纯文本选择
Reader
接下来明确要使用该体系中的哪个对象
明确设备:硬盘上的一个文件。 Reader体系中可以操作文件的对象是 :FileReader
FileReader fr = new FileReader(“a.txt");
BufferedReader bufr = new BufferedReader(fr);
目的是文件:OutPutStream 和 Writer
若果是纯文本: Writer
设备:硬盘,一个文件 可以使用Writer 体系中可以操作文件的对象FileWriter,接下来的动作是
FileWriter fr = new FileWriter(“b.txt");
如果需要提高效率: 使用BufferedReader();和BufferedWriter();
BufferedWriter bufw = new BufferedWriter(fw);
需求2:
将键盘录入的数据保存到一个文件中,这个需求中有源头和需求都存在
源头:InputStream Reader
因为键盘录入的是文本,所以是Reader
设备是键盘:对象时System.in , System.in 对应的应该是字节流,但是为了提高效率按照字符流操作比较方便,所以要把System点 in 转化为字符流。
用到了Reader 体系中的转换流叫做InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率就是用BufferedReader
BufferedReader(new InputStreamReader(System.in))
目的是: OutputStream 和 Writer
是文本的话用Writer
设备:硬盘,一个文件,使用FileWriter。
FileWriter fw = new FileWriter(”c.txt");
要提高效率使用
BufferedWriter bufw = new BufferedWriter(fw);
想要吧录入的数据按照指定的编码表(utf-8)将数据存放入文件中
目的是: OutputStream 和 Writer
是文本的话用Writer
设备:硬盘,一个文件,使用FileWriter。因为FileWriter 使用的是GBK。
但是存储时需要加入指定的编码表而指定的编码表只有转换流可以指定,所以要使用的对象是OutputStreamWriter。
效率提高:
BufferedWriter bufw = new BufferedWriter(osw);
由着四个类派生出来的子类名称都是与其父类名作为子类名的后缀
如 inputStream 的子类是FileInputStream
如 Reader 的子类FileReader。File是功能名字
区别,无论哪个字符都是用两个字节表示的
既然IO流用于操作数据的,数据最长体现的形式是文件。先以操作文件为主来掩饰,
需求:在硬盘上创建文件并且写入文字。
使用FileWriter
package SystemDemo;
import java.io.*;
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("demo.txt");
fw.write("abcdef");//先写到内存中的流里去了,
fw.flush();//刷新该流的缓冲临时的存放这些数据,使用flush就把这些临时存放的数据放入了目的地中去。
fw.write("haha");
fw.flush();
fw.close();//关闭流的资源,但是关闭之前会刷新一次内部的缓冲中的数据,使用了flush 可以继续使写write进文件,但是写close 之后就不能继续写write了
//使用close 的目的是关闭java自己调用的往文件中书写内容所调用的windows的资源。
}
}
结果是:
在E:\eclips 安装\IO也就是我的启动eclips的时候默认的文件放置的文件夹内会创建一个叫demo.txt 的文档文件。
实例1
IO异常处理和文件写入流程
package SystemDemo;
import java.io.*;
public class FileWriterDemo {
public static void main(String[] args) {
FileWriter fw = null;//在外边初始化,在内建立实例
try
{
fw = new FileWriter("E:\\demo.txt");
fw.write("abcdefg");
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally//finally 放关于资源的东西一定会被执行的程序
{
try{
if(fw!= null)
fw.close();//在try代码块的东西不能在finally直接调用
}
catch(IOException e){
System.out.println(e.toString());
}
}
}
}
结果是
在E盘中创建了一个叫做demo。txt的文件,fw.write()是写入的文件的内容,加try和catch 是因为,当调用写入程序的时候,java会跟系统自带的写入文件的程序联系,如果出现了异常就一定要被发现或者去处理。
最后的步骤就是关闭输入流,在关闭之前如果创建文件失败的话输入流就会在关闭的时候出现空指针异常,为了避免就要先写生只有在输入流是空的时候才关闭。
此外不能在finally的内部调用已经被实例化的写入流,因为如果实例化的写入流是空的或者是错误的,finally不能强制关闭。
实例2在已有的文件内续写新的内容
package SystemDemo;
import java.io.*;
public class FileWriterDemo3 {
public static void main(String[] args)throws IOException
{
//传递一个true参数,代表不覆盖已有的文件并且在已有文件的末尾进行数据的续写
FileWriter fw = new FileWriter("demo.txt",true);
fw.write("nihao\r\nxiexie");//运行一次就添加一次you但是空格没有被添加进去,在windows 不能单纯识别\n作为换行符
fw.close();
}
}
效果:
在原文件上继续书写了
nihao
谢谢
在FileWriter后面写上目标文件的名字再加上true就是续写,\r\n就是换行。
实例3如何读取全部内容
package FileReader;
import java.io.*;
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt");//如果不存在那个文件就给出IOnotfoundException
// int ch = fr.read();
// System.out.println("ch = "+(char)ch);
// int ch1 = fr.read();
// System.out.println("ch1 = "+ch1);//一次读一个继续往下读 如果到了末尾就返回-1
//方法1
// while(true)
// {
// int ch = fr.read();
// if(ch == -1)
// {
// break;
// }
// System.out.print((char)ch);
// }
//方法2
int ch = 0;
while((ch = fr.read())!= -1)
{
System.out.print((char)ch);
}
fr.close();
}
}
输出结果是:
a b c
bbb
和文本文档demo中的一模一样包括格式,从头读的,如果读到了-1 就是结束。
实例4 如何利用Char数组的方法快速读取全部的内容
package FileReader;
import java.io.*;
public class FileReader2 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt");
char[] buf = new char[1024];
int num =0;
while((num = fr.read(buf)) != -1)
{
System.out.println(new String(buf,0,num));
}
fr.close();
}
}
输出:
内容和demo中的一样
FileReader就像眼睛一样可以读取内容,但是每次读完之后都要有一个东西记住所读的内容,以前不利用数组的时候想 读取文件的全部内容必须挨个输出读到一次输出一个,如果利用了数组的话,就能够把读取到的东西先存放在数组中
fr.read(buf).意思就是FileRead 读了一个文件名字叫demo。txt 读这个文件的那个眼睛叫做fr,fr读到的内容放在一个char类型的数组中,数组的名字叫做buf。然后返回整个fr读取的字符数,也就是整个数组的长度。
如果读到了文件的末尾放入了一个空到数组中,fr.read(buf)就回返回-1。
利用如上方法判断出了最后的文件的末尾是哪,然后利用数组方法中部分取数组输出的方法输出数组中有内容的部分。
选择用1024 是因为1024 是2的10次方也就是1KB基本单位的长度。
实例5如何利用char 数组创建一个文件,然后再创建一个文件去拷贝第一次创建的文件的内容。
package CopyText;
import java.io.*;
public class CopyTexttry2 {
//创建一个txt 文件叫做ctt3内容是ctt3 然后复制到一个叫做ctt3copy.txt 的文件内,包括了各种出错自定义
public static void main(String[] args) throws IOException {
copy_3();
}
public static void copy_3() throws IOException{
FileWriter fw0 = new FileWriter ("E:\\ctt3.txt",true);
fw0.write("ctt3\r");
fw0.close();
FileWriter fw = null;
FileReader fr = null;
fr = new FileReader("E:\\ctt3.txt");
fw= new FileWriter("E:\\ctt3copy.txt");
try{
char [] cha = new char[1024];
int len = 0;
while((len = fr.read(cha))!= -1)
{
fw.write(cha,0,len);
}
}
catch(IOException e){
System.out.println("du xie shi bai "+e.toString());
}
finally{
if( fr != null)
try{
fr.close();
}
catch(IOException e){}
if( fw != null)
try{
fw.close();
}
catch(IOException e){}
}
}
}
输出结果是:
ctt3copy.txt
确实出现了内容就是ctt3
字符串缓冲区:
BufferedWriter 和 BufferedReader 就是具备缓冲技术的字符流
实力6 利用BufferWriter 创建文件并且写入内容
package BufferedWriter;
import java.io.*;
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("buf.txt");
//为了提高效率加入了缓冲数组只要将需要提高效率的对象传递给蝗虫去的构造函数即可。
BufferedWriter bufw = new BufferedWriter(fw);
// bufw.write("abcde");//newLine()方法是换行的,不同的系统里他是不同的东西,java 是\r\n在linux 里即使\r
// bufw.newLine();//就是换行
for(int x = 1;x<5;x++)
{
bufw.write("abce"+x);
bufw.newLine();
bufw.flush();
}
bufw.flush();
//其实关闭缓冲区就是在关闭缓冲区中的流对象。
bufw.close();//缓冲区的关闭是关闭提高效率的流对象
fw.close();
}
}
输出结果:
创建了buf.txt 文件在默认文件夹内,然后内容是
abce1
abce2
abce3
abce4
实例7 利用bufferedRead 和 bufferedWriter 拷贝文件
package BufferedWriter;
import java.io.*;
public class CopyTextByBuf {
public static void main(String[] args) {
BufferedReader bufr = null;
BufferedWriter bufw = null;
try
{
bufr = new BufferedReader(new FileReader ("SystemDemo.java"));
bufw = new BufferedWriter(new FileWriter("CTBB.txt"));
String strr = null;
while( (strr = bufr.readLine()) != null)
{
bufw.write(strr);
bufw.newLine();//加readline 方法就会返回信行方法之前的那一行内容。
bufw.flush();
}
}
catch(IOException e)
{
throw new RuntimeException("读写失败");
}
finally
{
try
{
if(bufr!= null)
bufr.close();
}
catch(IOException e)
{
throw new RuntimeException("读取关闭失败");
}
try
{
if(bufw!= null)
bufw.close();
}
catch(IOException e)
{
throw new RuntimeException("写入关闭失败");
}
}
}
}
输出效果:
打到目的了
注意:在每一次每一行输出后就要加
bufw.newLine();
不然的话就会把每一行的内容不带换行的连续放入到目标文件内。有了
bufw.newLine();
就在出现它之后自动换行。
装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于已有的功能,并提供加强功能,那么自定义的该类成为装饰类
装饰类通常会通过构造方法接受被装饰的对象,并且基于被装饰的对象的功能提供更强的功能。
装饰设计模式的意义在于,一个类出来之后,过一段时间如果想增加类的功能和方法,如果去修改此类会改变源代码底册设计有风险,而装饰设计模式提供了一种可能,不用去修改源代码,只是编写一个类其中类中包含原类,再把原来的类的方法放到新的方法中,之后调用新的类的新方法的时候就可以既有原来类的方法又有自己的新方法了。
实例:
package 装饰设计模式;
class Person{
public void chifan()
{
System.out.println("eat food");
}
}
public class PersonDemo {
public static void main(String[] args) {
Person p = new Person();
//p.chifan();
SuperPerson sp = new SuperPerson(p);
sp.superChifan();
}
}
class SuperPerson
{
private Person p;
SuperPerson(Person p)
{
this.p = p;
}
public void superChifan()
{
System.out.println("drink anchole");
p.chifan(); //System.out.println("eat food");
System.out.println("desert");
System.out.println("smoke");
}
}
输出结果
drink anchole
eat food
desert
smoke
上面的eat food 就是原来的方法的结果,而剩下的都是装饰类提供的方法效果。
LineNumberReader :
LineNumberReader 是一个bufferedReader 的子类,特点是能给出行号,还能设定行号。本身和BufferedReader 功能一样,但是可以给出一行的内容。
package LineNumberReader;
import java.io.*;
public class LineNumberReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("PersonDemo.java");
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
lnr.setLineNumber(0);
while((line = lnr.readLine())!= null)
{
System.out.println(lnr.getLineNumber()+line);
}
lnr.close();
}
}
输出结果:
1package 装饰设计模式;
2
3class Person{
4 public void chifan()
5 {
6 System.out.println("eat food");
7 }
8
9
10}
11
12public class PersonDemo {
13
14 public static void main(String[] args) {
15 Person p = new Person();
16 //p.chifan();
17 SuperPerson sp = new SuperPerson(p);
18 sp.superChifan();
19 }
20
21}
22class SuperPerson
23{
24 private Person p;
25 SuperPerson(Person p)
26 {
27 this.p = p;
28 }
29 public void superChifan()
30 {
31 System.out.println("drink anchole");
32 p.chifan(); //System.out.println("eat food");
33 System.out.println("desert");
34 System.out.println("smoke");
35
36
37 }
38}
可以看到和上面的单例设计模式例子的内容一模一样,并且添加了行号,如果set内加了100 就是从100 开始算了。
IO里边的对象举个例子来看
MyReader 专门是为了用于读取数据的对象,数据有很多种为了分别描述对不同数据的描述比如MyTextReader,MyMediaReader都有读的功能但是方式不同,向上抽取都有父类MyReader,为了各自提高效率我们想到了缓冲技术,MyBufferedTextReader 和 MyBufferedMediaReader 后期我可能出现一个MyDataReader 带着MyBufferedDataReader整个体系虽然能用但是要进行优化,上边的体系是继承方法创建的体系,他们的技术都是一样的都是Buffered可以单独的弄一个MyBufferedReader 比如
Class MyBufferedReader
{
MyBufferedReader(MyTextReader){}
MyBufferedReader(MyMediaReader media){}
}
麻烦不好 扩展性差,找到其参数的共同性,通过多态的形式提高扩展性。
Class MyBufferedReader exten Myreader
{
private MyReader r;
MyBufferedReader(MyReader r){}//MyReader 是其他所有的MyTextReader,MyMediaReader等类的父类所以都能被MyBufferedReader 扩展所以方便
新的模式比继承的模式要灵活继承了继承体系的臃肿,而且降低了类和类之间的关系。
继承体系
装饰设计模式
显而易见装饰设计模式更简单灵活,避免了继承体系的复杂装饰类因为增强了已经有的对象功能和已有的相同只不过提供了更强的功能,装饰类和被装饰类都属于同一个体系
装饰设计模式实例:需求设计一个类装饰类可以去实现LineNumberReader的功能但是有可以有自己的特殊地方,比如可以只要输出的话肯定每一行前面都有行数和冒号
package heimaceshiti;
import java.io.*;
public class MyLineNumberReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("stu.txt");
MyLineNumberReader mylnr = new MyLineNumberReader(fr);
String line = null;
while((line = mylnr.myReadLine())!= null)
{
System.out.println(mylnr.getLineNumber()+":"+line);
}
mylnr.myClose();
}
}
class MyLineNumberReader
{
private Reader r;
private int lineNumber;
MyLineNumberReader(Reader r)
{
this.r = r;
}
public String myReadLine() throws IOException
{
lineNumber++;
StringBuilder sb = new StringBuilder();
int ch = 0;
while((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;
}
public void setLineNumber(int lineNumber)
{
this.lineNumber = lineNumber;
}
public int getLineNumber()
{
return lineNumber;
}
public void myClose() throws IOException
{
r.close();
}
}
输出结果:
1:姓名 语文 数学 英语 总分
2:ds 2.0 3.0 11.0 16.0
3:w 1.0 2.0 3.0 6.0
4:e 2.0 3.0 1.0 6.0
每一行都有冒号。
import java.io.*;
public class MyBufferedReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("stu.txt");
MyBufferedReader myBuf = new MyBufferedReader(fr);
String line = null;
while((line = myBuf.myReadLine())!= null)
{
System.out.println(line);
}
myBuf.myClose();
}
}
class MyBufferedReader extends Reader
{
private Reader r;
MyBufferedReader(Reader r) throws IOException
{
this.r = r;
}
//一次读一行数据的方法
public String myReadLine() throws IOException
{
//第一一个临时容器,原BufferedReader 封装的是字符数组。
//为了掩饰方便定义一个StringBuilder 容器,微微可以把数据变成字符串
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch= r.read())!= -1)
{
if(ch=='\r')//换行就不存 r 是回车将光标移动到下一行前面所以继续
continue;
if(ch=='\n')
return sb.toString();//n是结束吧光标移动到下一行
//的末尾所以要变字符串
else
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 r.read(cbuf,off,len);
}
@Override
public void close() throws IOException {
// TODO Auto-generated method stub
}
}
输出结果:
姓名 语文 数学 英语 总分
ds 2.0 3.0 11.0 16.0
w 1.0 2.0 3.0 6.0
e 2.0 3.0 1.0 6.0
字节流:
InputStream 和 OutputStream 字节流使用的是字节数组, 字节流不需要刷新(flush())方法就能输入到文本文件里。字节流没有缓冲区,可以直接把字节一步一步的写到目的地,字节流可以操作媒体文件,
构造方法摘要 | |
---|---|
FileInputStream(File file) 通过打开一个到实际文件的连接来创建一个 FileInputStream ,该文件通过文件系统中的 File 对象 file 指定。 | |
FileInputStream(FileDescriptor fdObj) 通过使用文件描述符 fdObj 创建一个 FileInputStream ,该文件描述符表示到文件系统中某个实际文件的现有连接。 | |
FileInputStream(String name) 通过打开一个到实际文件的连接来创建一个 FileInputStream ,该文件通过文件系统中的路径名 name 指定。 |
方法摘要 | |
---|---|
int | available() 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。 |
void | close() 关闭此文件输入流并释放与此流有关的所有系统资源。 |
protected void | finalize() 确保在不再引用文件输入流时调用其 close 方法。 |
FileChannel | getChannel() 返回与此文件输入流有关的唯一 FileChannel 对象。 |
FileDescriptor | getFD() 返回表示到文件系统中实际文件的连接的 FileDescriptor 对象,该文件系统正被此 FileInputStream 使用。 |
int | read() 从此输入流中读取一个数据字节。 |
int | read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。 |
int | read(byte[] b, int off, int len) 从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。 |
long | skip(long n) 从输入流中跳过并丢弃 n 个字节的数据。 |
从类 java.io.InputStream 继承的方法 |
---|
mark, markSupported, reset |
从类 java.lang.Object 继承的方法 |
---|
clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
FileOutputStream
构造方法摘要 | |
---|---|
FileOutputStream(File file) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 | |
FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 | |
FileOutputStream(FileDescriptor fdObj) 创建一个向指定文件描述符处写入数据的输出文件流,该文件描述符表示一个到文件系统中的某个实际文件的现有连接。 | |
FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流。 | |
FileOutputStream(String name, boolean append) 创建一个向具有指定 name 的文件中写入数据的输出文件流。 |
方法摘要 | |
---|---|
void | close() 关闭此文件输出流并释放与此流有关的所有系统资源。 |
protected void | finalize() 清理到文件的连接,并确保在不再引用此文件输出流时调用此流的 close 方法。 |
FileChannel | getChannel() 返回与此文件输出流有关的唯一 FileChannel 对象。 |
FileDescriptor | getFD() 返回与此流有关的文件描述符。 |
void | write(byte[] b) 将 b.length 个字节从指定 byte 数组写入此文件输出流中。 |
void | write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。 |
void | write(int b) 将指定字节写入此文件输出流。 |
实力:使用字节流创建并且读取创建的文件。
package FileOutputStream;
import java.io.*;
//需求:想要操作图片数据,需要字节流
public class FileStream {
public static void main(String[] args)throws IOException {
writeFile();
//readFile_1();
//readFile_2();
readFile_3();
}
public static void readFile_1() throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
int ch = 0;
while((ch = fis.read())!= -1)
{
System.out.println((char)ch);
}
fis.close();
}
public static void readFile_2() throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
byte [] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf))!= -1)
{
System.out.println(new String(buf,0,len));
}
fis.close();
}
public static void readFile_3() throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
int num = fis.available();
byte [] buf = new byte[num];
System.out.println("num: "+num);
fis.read(buf);
System.out.println(new String(buf));
fis.close();
}
public static void writeFile() throws IOException//创建文件
{
FileOutputStream fos = new FileOutputStream("fos.txt");//名字叫fos
fos.write("abcde".getBytes());
fos.close();
}
}
输出:
num: 5
abcd
我们的writeFile()方法就是创建一个文件基本上和字符流一样的方法,写入的过程内容后面要加上getBytes(),此外,available()方法可以返回文件的内容长度,然后根据内容长度来一次性的创建一个等长的数组,然后一次输出这个大数组的内容就能完整的得到文件内容了,问题是虚拟机的分配空间默认的是64兆,如果数组太大会出现内存溢出,所以使用1024的整数倍的数组是比较折中比较好的选择。所以readFile_2 推荐,readFile_3 慎用。
使用字节流拷贝文件:
实例:使用字节楼拷贝文件
package FileOutputStream;
import java.io.*;
public class CopyPic {
public static void main(String[] args) throws IOException{
FileOutputStream fos = null;
FileInputStream fis = null;
try{
fos = new FileOutputStream("b.JPEG");// 我这个就打开看不到咋弄的
fis = new FileInputStream("a.JPEG");
// fos = new FileOutputStream("E:\\qq1.bmp");
// fis = new FileInputStream("E:\\qq11.bmp");
// fos = new FileOutputStream("QQ11.bmp");
// fis = new FileInputStream("QQ1.bmp");
//
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf))!= -1)
{
fos.write(buf, 0, len);
}
}
catch(IOException e)
{
System.out.println("复制文件失败");
}
finally{
try{
if(fis != null)
fis.close();
}
catch(IOException e)
{
System.out.println("读关闭失败");
}
try{
if(fos != null)
fos.close();
}
catch(IOException e)
{
System.out.println("写入关闭失败");
}
}
}
}
使用字符流拷贝媒体文件,因为使用字符流的话,字符流会去对照编码表去拷贝,有的字符在编码表没有,所以有的字符在拷贝过程中会不一样,结果就是文件打不开或者文件错误。
字节流转化为字符流:
通过刚才键盘录入一行数据并打印其大写,发现其实就是读一行原理,就是readLine方法,能不能直接使用readLine方法来完成键盘录入一行数据的读取呢?readLine方法是字符流BufferedReader 类中的方法。而键盘录入的read 方法是字节流InputStream的方法为什么不能将字节流转成字符流在使用字符流缓冲区中的readLine 方法呢?
方法就是利用InputStreamReader,它是字节流转化为字符流的桥梁,方法和Reader 一样。
实力:利用InputStreamReader 把字节流转化为字符流
package 字节流转化为字符流;
import java.io.*;
public class TransStreamDemo {
public static void main(String[] args) throws IOException {
//获取键盘录入对象
InputStream in = System.in;
InputStreamReader isr = new InputStreamReader(in);
//为了提高效率将字符串进行缓冲区技术高效操作,使用BufferedReader
BufferedReader bufr = new BufferedReader(isr);
String line = null;
while((line = bufr.readLine())!= null)
{
String over = "over";
if(over.equals(line))
break;
System.out.println(line.toUpperCase());
}
bufr.close();
}
}
结果:
a
A
b
B
c
C
over
输入over就能结束。程序的输入源流是键盘,目的是控制台。
字节流转化为字符流:
需求:把键盘输入的大写华并且输出到控制台上去。
package 字节流转化为字符流
import java.io.*;
public class TransStreamDemo1 {
public static void main(String[] args) throws IOException {
//获取键盘录入对象
BufferedReader bufr = new BufferedReader(new InputStreamReader( System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));//简单方式
String line = null;
while((line = bufr.readLine())!= null)
{
String over = "over";
if(over.equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
输出结果:
ds
DS
dsd
DSD
over
下次写键盘输入的话就写BufferedReader(new InputStreamReader(System.in));
字符流转化为为字节流2
package 字节流转化为字符流;
import java.io.*;
public class TransStreamDemo2 {
public static void main(String[] args) throws IOException {
BufferedReader bufr = new BufferedReader(new InputStreamReader( System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter( new FileOutputStream("out.txt"),"UTF-8"));
String line = null;
while((line = bufr.readLine())!= null)
{
String over = "over";
if(over.equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
输出结果
控制面板输入
f
sd
over
得到文件内容为
f
sd
利用System.setIn/setOut 方法更改和拷贝源文件。
使用System点set的方法可以更改上面的代码,如果我们不想用控制面板输出了而是想把以前用控制面板输出的程序更改为利用已有的文件作为输出源文件 方法是System.set方法
package 使用System点set方法拷贝文件;
import java.io.*;
public class UsingSystemsetCopy {
public static void main(String[] args) throws IOException {
System.setIn(new FileInputStream("demo.txt"));
System.setOut(new PrintStream("democopy.txt"));
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(System.out));
String str = null;
while((str = bfr.readLine())!= null)
{
bfw.write(str);
bfw.newLine();
}
bfr.close();
bfw.close();
}
}
结果:
demo确实被拷贝到了democopy中。
File 类:
用来将文件和文件夹封装成对象的类,方便对文件和文件夹操作,file 对象可以作为参数传递给流的构造函数。file 类可以操作文件和文件夹的属性信息,弥补了流对象的不足因为流对象不能操作文件夹,不能操作文件的属性信息,比如文件的可读可写等。流只能操作数据,操作封装成文件的信息只能用file类
File 类的常见方法:
1 创建
boolean creatNewFile();:在指定位置创建文件,若该文件已经存在,则不创建返回false和输出流对象不一样,输出流一建就创立文件,如果文件已经存在则覆盖
boolean mkdir():创建文件 boolean mkdirs()创建多级文件夹
2 删除
boolean delete():删除失败返回false
void deleteOnExit():程序退出的时候删除指定文件
3 判断
boolean exsits();文件是否存在。
isFile():判断是否是文件
isDirectory():判断是否是文件夹
4 获取信息
getNam()
getPath()获取自己的路径
getParent() 获取父路径
lastModified()获取最后一次的时间
实力验证File 方法
package File类;
import java.io.*;
public class FileDemo {
public static void main(String[] args) throws IOException {
//将a.txt封装成file 对象,不一定存在,可以将已有的和未出现的文件或者文件夹封装成对象
File f1 = new File("a.txt");
//左边是父目录,右边是文件名 f2是将目录和文件分看传递,特点是文件可以变化。
File f2 = new File("E:\\abc","b.txt");
File d = new File("E:\\abc");
File f3 = new File(d,"c.txt");
File f4 = new File("E:"+File.separator+"abc"+File.separator+"f4.txt");
sop("f1:"+f1);
sop("f2:"+f2);
sop("f3:"+f3);
sop("f3:"+f4);
//method_1();
// method_2();
method_5();
}
public static void method_5() throws IOException
{
File f1 = new File("E:\\demo.txt");
File f2 = new File("IOdemo.txt");
sop("rename:"+f1.renameTo(f2));// 把f1中的文件内容放到f2中,并且删除f1 的内容,f1的内容必须有f2可以没有
}
public static void method_4() throws IOException
{
File f = new File("abc\\file.txt");
sop("path:"+f.getPath());
sop("abspath:"+f.getAbsolutePath());// 把所在文件的父目录现实出来,父目录一直到硬盘名字 文件是否存在都能显示出来
sop("parent:"+f.getParent());//获取父目录中的绝对路径 单只上一次目录的路径,如果相对路径中有上一层目录那么该目录就是返会结果
}
public static void method_3() throws IOException
{
File f = new File("file.txt");
//f.createNewFile();
f.mkdir();// 文件夹也可以命名为 file点txt
//在判断文件对象是否是文件或者是文件夹的时候必须先判断该对象是否存在,通过exists判断。
sop("dir:"+f.isDirectory());
sop("file:"+f.isFile());
sop("isabsoulte:"+f.isAbsolute());
}
public static void method_2()
{
File f = new File("file.txt");
//sop("excute "+f.canExecute());//文件不存在则不能执行
sop("exists:"+f.exists());
// //创建文件夹
// File dir = new File("abc");//已有的文件夹之下一层可以创建,多级不能创建文件夹
// sop("dir.mkdir():"+dir.mkdir());
File dir1 = new File("abc\\a\\b\\c");//已有的文件夹之下一层可以创建,支持多级创建
sop("dir.mkdirs():"+dir1.mkdirs());
}
public static void method_1() throws IOException
{
File f= new File("file.txt");
//f.deleteOnExit();//告诉虚拟机,在退出的时候给我删了只要文件不运行了都会删除,为了文件退出的时候能够自动删除
sop("create:"+f.createNewFile());
//sop("delete:"+f.delete());
//放在finally 不见得都能删,如果程序在被应用过程中删除不了,因为文件正在被流操作,
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
File 类演示2
package File类;
import java.io.*;
public class FileDemo2 {
public static void main(String[] args) {
listDemo();//使用listfile 方法现实一个文件内的所有文件
// showHD();//显示所有的硬盘
// listDemo2();//给出所有的点txt 结尾的文件
//显示文件名和文件的大小
// File dir = new File("E:\\");
// File[] files = dir.listFiles();
// for(File f: files)
// {
// System.out.println(f.getName()+"::"+f.length());
// }
//显示文件夹内的所有文件能够分级的现实
// File dir = new File("E:\\eclips 安装\\IO");
// showDir(dir,0);
//
//递归演示
//toBin(6);
//System.out.println(getSum(3));
//递归演示结束
}
// 展示目录中的所有的内容,在列出的过程中出现目录的话还可以再次调用自身的功能,这种变成办法叫做递归
public static String getLevel(int level)
{
StringBuilder sb = new StringBuilder();
sb.append("|== ");
for(int x = 0;x<level;x++)
{
sb.insert(0, "| ");
}
return sb.toString();
}
public static void showDir(File dir, int level)
{
System.out.println(getLevel(level)+dir.getName());
level++;
File[] files = dir.listFiles();
for(int x = 0 ;x<files.length;x++)
{
if(files[x].isDirectory())
{
showDir(files[x],level);
}
else
System.out.println(files[x]);
}
}
public static void listDemo2()
{
File dir = new File("E:\\eclips 安装\\IO");
String[] arr = dir.list (new FilenameFilter()
{
public boolean accept(File dir,String name)
{
return name.endsWith(".txt");
}
});
System.out.println("len:"+arr.length);
for(String name: arr)
{
System.out.println(name);
}
}
public static void listDemo()
{
File f = new File("E:\\");
String[] names = f.list();//调用list 方法的file对象必须是封装了一个已经存在的目录
for(String name: names)
{
System.out.println(name);
}
}
public static void showHD()
{
File[] files = File.listRoots();
for(File f:files)
{
System.out.println(f);//输出机器里有效的盘符
}
}
//递归开始
public static int getSum(int n )
{
int x = 0;
if(n == 1)
return 1;
x = n+getSum(n-1);
return x;
}
public static void toBin(int num)
{
if(num>0)
{
toBin(num/2);
System.out.println(num%2);
num = num/2;
}
}
//递归结束
}
File删除
windows删除目录从里往外面删除,既然是从里往外删除就需要用到递归,
package File类;
import java.io.File;
public class RemoveDir {
public static void main(String[] args) {
File dir = new File("mydir1");
removeDir(dir);
}
public static void removeDir(File dir)
{
File[] files = dir.listFiles();
for(int x = 0; x<files.length;x++)
{
if(!(files[x].isHidden()) && files[x].isDirectory())//避免隐藏的被删除
removeDir(files[x]);
else System.out.println(files[x].toString()+":files delete:"+files[x].delete());
}
System.out.println(dir+":files delete:"+dir.delete());
}
}
File 演示把某个文件夹的目录打印在一个文件里
package 建立java列表清单;
import java.io.*;
import java.util.*;
//文件名称和路径放在一个文件内因为windows搜素慢
/*
* 思路
* 1对指定的目录递归
* 2获取递归过程中的java文件的路径
* 3路径储存到集合中
* 4集合写入到文件中
*/
public class SeflTryJavaFileListTxt {
public static void sop(Object obj)
{
System.out.println(obj);
System.out.print("");
}
public static void main(String[] args) throws IOException {
File file = new File("E:\\eclips 安装\\IO");
File [] files = file.listFiles();
List<File> lis = new ArrayList();
fileToList(file,lis);//把文件夹中的内容都放在刚才建立的数组中
consoleshow(lis);//为了在控制面板上展示要求文件夹中的内容
writeToFile(lis,"MyjavaListFile.txt");// 把数组中的内容都放在一个叫做MyjavaListFile.txt的文件中
}
public static void consoleshow(List<File> lis)
{
Iterator<File> it = lis.iterator();
while(it.hasNext())
{
sop(it.next());
}
}
public static void fileToList(File dir,List<File> list)//创建一个类名字叫fileToList(File dir,List<File> list)
//把文件夹中的东西放在一个File类的数组中,然后遍历该数组中的元素,如果是dir 则迭代,如果是文件并且以java 为结尾的就放在集合中
{
File [] files = dir.listFiles();
for(File f : files)
{
if(f.isDirectory())
{fileToList(f, list);}
else
{
if(f.toString().endsWith(".java"))
list.add(f);
}
}
}
public static void writeToFile(List<File> list,String MyjavaListFile) throws IOException
{
// 把list 中的内容放在一个文件名字叫做javaListFile中
BufferedWriter bufw = null;
try{
bufw = new BufferedWriter(new FileWriter(MyjavaListFile));
String str;
for(File f : list) // 用增强For循环可以做并且方便推荐用
{
str = f.getAbsolutePath();
bufw.write(str);
bufw.newLine();
bufw.flush();
}
/*//用迭代器也可以带出所有的内容但是麻烦因为还要写一行迭代器。不推荐用
Iterator<File> it = list.iterator();
while(it.hasNext())
{
str = it.next().getAbsolutePath();
bufw.write(str);
bufw.newLine();
bufw.flush();
}
*/
}
catch(IOException e)
{
throw new RuntimeException("读写失败");
}
finally{
try
{
if(bufw!= null)
bufw.close();
}
catch(IOException e)
{
throw new RuntimeException("读取关闭失败");
}
}
}
}
扩展对象
Properties:
Properties是哈希table 的子类 记录了文件的属性,比如字体,颜色等等,我们可以使用一些方法去修改文件的属性
package 扩展对象;
import java.io.*;
import java.util.*;
import java.util.Properties;
public class PropertiesDemo {
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args) {
setAndGet();
}
//设置和获取元素
public static void setAndGet()
{
Properties prop = new Properties();
prop.setProperty("zhangsan", "30");
prop.setProperty("lisi", "39");
// sop(prop);
prop.setProperty("lisi",89+"");
String value = prop.getProperty("lisi");
sop(value);
Set<String> names = prop.stringPropertyNames();
for(String s : names)
{
sop(s+prop.getProperty(s));
}
}
}
输出结果:
89
zhangsan30
lisi89
这些可以显示出property 的内容,使用set 后再使用get 方法。
实例 运行此时的记录,如果使用次数已到就给出注册提示
容易想到的是计数器,但是计数器的问题是它定义在程序中随着程序的运行而在内存中存在并进行了自增,随着该程序的结束该计数器就也在内存中消失了,下一次再启动该程序又会从新计数,我们的想法是把计数器的数字记录到一个文件中,每次启动程序都把这个文件当中的记录上继续增加计数然后再返回给记录文件中。该配置文件使用键值对的形式这样便于阅读并且操作数据。
键值对数据是Map集合,数据是以文件的形式存储,使用IO技术,map+io 就是properties 的技术应用,配置文件可以实现应用程序数据的共享。
package 扩展对象;
import java.io.*;
import java.util.*;
public class RunCount {
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args) throws IOException {
Properties prop = new Properties();
File file = new File("count.ini");
if(!(file.exists()))
file.createNewFile();
FileInputStream fis =new FileInputStream("count.ini");//扩展名就是集合名称
prop.load(fis);
int count = 0;
String value = prop.getProperty("time");//time 是key
if(value != null)
{
count= Integer.parseInt(value);
if(count>=5)
{
sop("5 次已到,拿钱");
return;
}
}
count++;
prop.setProperty("time", count+"");
FileOutputStream fos = new FileOutputStream(file);
prop.store(fos, "");
fos.close();
fis.close();
}
}
输出结果:
5 次已到,拿钱
有了一个文件叫做
count.ini
内容是
#
#Sun Dec 14 23:41:25 CST 2014
time=5
打印流
该流提供了打印的方法,可以将各种数据类型的数据都原样打印,
字节打印流:
PrintStream
构造函数可以接受的参数类型
1 file 对象,能直接打印文件,
2 字符床路径 String
3 字节输出流 OutputStream
字符打印流:也叫字符输出流在web开发常用,打印到客户端供客户查看。
PrintWriter
1 file 对象,能直接打印文件,
2 字符床路径 String
4 字符输出流,Writer
System out 就返回PrintStream
下面是PrintWriter 的构造方法
构造方法摘要 | |
---|---|
PrintWriter(File file) 使用指定文件创建不具有自动行刷新的新 PrintWriter。 | |
PrintWriter(File file, String csn) 创建具有指定文件和字符集且不带自动刷行新的新 PrintWriter。 | |
PrintWriter(OutputStream out) 根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。 | |
PrintWriter(OutputStream out, boolean autoFlush) 通过现有的 OutputStream 创建新的 PrintWriter。 | |
PrintWriter(String fileName) 创建具有指定文件名称且不带自动行刷新的新 PrintWriter。 | |
PrintWriter(String fileName, String csn) 创建具有指定文件名称和字符集且不带自动行刷新的新 PrintWriter。 | |
PrintWriter(Writer out) 创建不带自动行刷新的新 PrintWriter。 | |
PrintWriter(Writer out, boolean autoFlush) 创建新 PrintWriter。 |
可以看出PrintWriter 构造函数中可以有file 类,有OutputStream 类,还有String 类,还可以有Writer 类,
BufferedWriter,CharArrayWriter,FilterWriter,OutputStreamWriter,PipedWriter,PrintWriter,StringWriter
OutputStream 类包括
ByteArrayOutputStream,FileOutputStream,FilterOutputStream,ObjectOutputStream,OutputStream,PipedOutputStream
还包括System点out
实例:在控制台输入字母,在控制台输出大写的输入字母
package 打印流;
import java.io.*;
public class PrintStreamDemo {
public static void main(String[] args) throws IOException {
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(System.out);//System.out is PrintStream
String line = null;
while((line = bufr.readLine())!= null)
{
if("over".equals(line))
break;
out.println(line.toUpperCase());
out.flush();
}
out.close();
bufr.close();
}
}
out
public static final PrintStream out
-
“标准”输出流。此流已打开并准备接受输出数据。通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标。
对于简单独立的 Java 应用程序,编写一行输出数据的典型方式是:
System.out.println(data)
PrintWriter
public PrintWriter(OutputStream out, boolean autoFlush)
-
通过现有的 OutputStream 创建新的 PrintWriter。此便捷构造方法创建必要的中间 OutputStreamWriter,后者使用默认字符编码将字符转换为字节。
-
参数:
-
out
- 输出流 -
autoFlush
- boolean 变量;如果为 true,则 println、 printf 或 format 方法将刷新输出缓冲区
另请参见:
-
//和上面的程序基本一样只不过PrintWriter 有一个自动刷新缓冲区的构造函数。<pre name="code" class="java">//System.out 后面加true 就可以了然后去掉flush
package 打印流;import java.io.*;public class PrintStreamDemo {public static void main(String[] args) throws IOException {BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));PrintWriter out = new PrintWriter(System.out,true);//System.out is PrintStream String line = null;while((line = bufr.readLine())!= null){if("over".equals(line))break;out.println(line.toUpperCase());//out.flush();}out.close();bufr.close();}} 输出结果:
a点txt 在默认文件夹被创建出来,在不输入over以前,a文件依然会刷新并且存入每次的printwriter 的输入内容。
实例:在PrintWriter 拷贝输入文字到一个文件中
package 打印流;
import java.io.*;
public class PrintStreamDemo {
public static void main(String[] args) throws IOException {
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new BufferedWriter( new FileWriter("a.txt")),true);//System.out is PrintStream 吧文件封装到流里也可以自动刷新
String line = null;
while((line = bufr.readLine())!= null)
{
if("over".equals(line))
break;
out.println(line.toUpperCase());
//out.flush();
}
out.close();
bufr.close();
}
}
输出结果:
a点txt 在默认文件夹被创建出来,在不输入over以前,a文件依然会刷新并且存入每次的printwriter 的输入内容。
基本上就是在PW内多次使用其Writer。
SequenceInputStream
可以把很多流合并到一个流中,整个合并后的文件就是 SequenceInputStream
java.io
类 SequenceInputStream
java.lang.Objectjava.io.InputStream
java.io.SequenceInputStream
-
所有已实现的接口:
- Closeable
public class SequenceInputStream extends InputStream
SequenceInputStream
表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
-
从以下版本开始:
- JDK1.0
构造方法摘要 | |
---|---|
SequenceInputStream(Enumeration<? extends InputStream> e) 通过记住参数来初始化新创建的 SequenceInputStream ,该参数必须是生成运行时类型为 InputStream 对象的Enumeration 型参数。 | |
SequenceInputStream(InputStream s1, InputStream s2) 通过记住这两个参数来初始化新创建的 SequenceInputStream (将按顺序读取这两个参数,先读取 s1 ,然后读取s2 ),以提供从此SequenceInputStream 读取的字节。 |
方法摘要 | |
---|---|
int | available() 返回不受阻塞地从当前底层输入流读取(或跳过)的字节数的估计值,方法是通过下一次调用当前底层输入流的方法。 |
void | close() 关闭此输入流并释放与此流关联的所有系统资源。 |
int | read() 从此输入流中读取下一个数据字节。 |
int | read(byte[] b, int off, int len) 将最多 len 个数据字节从此输入流读入 byte 数组。 |
合并流的实例
package 合并流SequenceInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
public class 网上的用throws的方法写的 {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/**
* 需求:将多个文件数据进行合并到一个文件中。
*
* SequenceInputStream构造方法:
* SequenceInputStream sis = new SequenceInputStream(Enumeration<? extends InputStream> e);//枚举变量参数
*/
show1();
// show2();
//show3();
}
public static void show3() throws IOException {
ArrayList<InputStream> al = new ArrayList<InputStream>();
for(int i = 1 ; i<4 ; i++){
al.add(new FileInputStream(i+".txt"));
}
Enumeration<InputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);//将三个数据源合并到一个数据源
FileOutputStream fos = new FileOutputStream(new File("4.txt"));
int len = 0;
byte []bu = new byte[1024];
while((len = sis.read(bu))!=-1){
fos.write(bu, 0, len);
}
sis.close();
fos.close();
}
public static void show2() throws IOException {
ArrayList<InputStream> al = new ArrayList<InputStream>();
for(int i = 1 ; i<4 ; i++){
al.add(new FileInputStream(i+".txt"));
}
final Iterator<InputStream> it = al.iterator(); //内部类访问外部类中的成员变量,需要用final 修饰。
Enumeration<InputStream> en = new Enumeration<InputStream>() {
@Override
public boolean hasMoreElements() {
return it.hasNext();
}
@Override
public InputStream nextElement() {
return it.next();
}
};
SequenceInputStream sis = new SequenceInputStream(en);//将三个数据源合并到一个数据源
FileOutputStream fos = new FileOutputStream(new File("4.txt"));
int len = 0;
byte []bu = new byte[1024];
while((len = sis.read(bu))!=-1){
fos.write(bu, 0, len);
}
sis.close();
fos.close();
}
public static void show1() throws IOException {
Vector<InputStream> v = new Vector<InputStream>();
v.add(new FileInputStream("1.txt"));
v.add(new FileInputStream("2.txt"));
v.add(new FileInputStream("3.txt"));
Enumeration<InputStream> en = v.elements();//获得枚举变量
SequenceInputStream sis = new SequenceInputStream(en);//将三个数据源合并到一个数据源
FileOutputStream fos = new FileOutputStream(new File("4.txt"));
int len = 0;
byte []bu = new byte[1024];
while((len = sis.read(bu))!=-1){
fos.write(bu, 0, len);
}
sis.close();
fos.close();
}
}
输出结果:
是有一个文件交4点txt被创建并且内容是 1 2 3 点txt的一次连接的内容。
注意类的名字不是是InputStream 不然会出现类undefined异常,show 1,3 推荐使用但是show1 不能把几个合并在一起,并且不引入新的文件。show2 推荐吧几个合并在一起可以不引入新文件
分割流
分割流的作用是把一个整个的流拆成多个流,然后输入到几个独立的文件中
分割流实例:
package 流切割SplitFile;
import java.util.*;
import java.io.*;
public class SplitFileShow {
public static void main(String[] args) throws IOException {
splifFile();
merge();
}
public static void merge() throws IOException
{
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x= 1;x<=1;x++)
{
al.add(new FileInputStream(x+"sf.doc"));
}
Iterator<FileInputStream> it = al.iterator();
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
SequenceInputStream sis= new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("0.doc");
int len = 0;
byte[] buf = new byte[1024];
while((len = sis.read(buf))!= -1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
public static void splifFile() throws IOException
{
FileInputStream fis = new FileInputStream("sf.doc");
FileOutputStream fos = null;
byte[] buf = new byte[1024*500];
int len = 0;
int count =1;
while((len = fis.read(buf))!= -1)
{
fos = new FileOutputStream((count++)+"sf.doc");//如果源文件是图片或者音乐这个文件的名字就不能是bmp或者mp3
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
}
结果是:
有根据byte数组的大小来分文件的大小
操作对象:
ObjectInputStream 和 ObjectOutputStream 被操作的对象需要实现Serializable接口,他们是可以直接操作对象的流
对象本身存在堆内存,操作完毕后释放了内存对象就会消失,而对象操作流能把内存上的对象存到硬盘上,下次用这个对象的时候只要读取那个硬盘上的文件就可以了,
这个叫做对象的持久化,序列化,和可串行性。他们是相互使用的只能使用对方去读和写。
实例吧一个Person类存入文件中
package 内存中对象的硬盘化操作;
import java.io.Serializable;
class TarPerson implements Serializable//没有方法的接口,又叫做标记接口就是给一个类盖一个戳意思是具备资格可以序列化,跟猪肉一样盖章的才能吃才干净,给类加了一个
//serialVersionUID 这个类就有了一个ID表示,整个ID表示给编译器用,类被持久化之后类可以被改变,我每次重新改变的类和以前的持久化的类有可能不一样,所以需要一个ID号去区别
//class
/*
* class
* uid = 121; new 一个 obj 对象,有属性然后这个对象被序列化到了一个文件里边去了,就被持久化了
*之后加了name,age,等改变了Uid 也就改变了
*/
{
static final long serialVersionUID = 42L;//UID就被固定了,之后再改类中的内容UID也不会改变 新的类就能去操作曾经序列化的对象
private String name;
transient int age;//transient 保证age 值在对内存中存在,不会被序列化了。
static String country = "cn";
TarPerson(String name,int age,String country)
{
this.name = name;
this.age = age;
this.country = country;
}
public String toString() {
return name+":"+age+":"+country;
}
}
操作类
package 内存中对象的硬盘化操作;
import java.io.*;
public class ObjectStreamDemo {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
//writeObj();
readObj();
//
}
public static void readObj() throws FileNotFoundException, IOException, ClassNotFoundException
{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Obj.txt"));
TarPerson p =(TarPerson)ois.readObject();
System.out.println(p);
ois.close();
}
public static void writeObj() throws FileNotFoundException, IOException
{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Obj.txt"));//只要不是人类看的懂得文件都不是纯文本文件,都要使用字节流
oos.writeObject(new TarPerson("lisi",3001,"kr"));
oos.close();
}
}
输出结果:
obj点txt 文件存在了,内容是乱码,在控制面板能输出
"lisi",3001,"kr"
管道流:
PopeInputStream 和PipedOutStream
读写的时候写入和输出没关系,中间需要中专,管道流两个流可以接上,写的写读的就可以读到,建议用多线程操作不然出现死锁问题
package 管道流PipedSreamDemo;
import java.io.*;
class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream in)
{
this.in = in;
}
public void run()
{
try{
byte[] buf = new byte[1024];
System.out.println("读取前。。。无数据阻塞");
int len = in.read(buf);
System.out.println("读到数据。。。阻塞结束");
String s = new String (buf,0,len);
System.out.println(s);
in.close();
}
catch(IOException e)
{
throw new RuntimeException("管道读取流失败");
}
}
}
class Write implements Runnable
{
private PipedOutputStream out;
Write(PipedOutputStream out)
{
this.out = out;
}
public void run()
{
try{
System.out.println("开始写入数据等待六秒后");
Thread.sleep(6000);
out.write("guandao lai le ".getBytes());
out.close();
}
catch(Exception e)
{
throw new RuntimeException("管道输出失败");
}
}
}
public class PopedStreamDemo {
public static void main(String[] args) throws IOException {
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);
Read r = new Read(in);
Write w= new Write(out);
new Thread(r).start();
new Thread(w).start();
}
}
输出结果:
读取前。。。无数据阻塞
开始写入数据等待六秒后
读到数据。。。阻塞结束
guandao lai le
写入数据流会直接写入到读取数据流里,结果是读取数据流直接读取写入数据流的内容。
RandomAccessFile
目的是可以让数据能分段写入,吧数据分成段后一个线程去负责一段数据,让多个线程去负责多个数据的写入,互相不会冲突,这个东西就是下载软件的原理,多个线程去写数据到客户端的硬盘里
随机访问文件不是IO的子类,直接继承object,此类的实力支持随机访问文件的读取和写入,既能读又能写,封装了数组和指针,给数组的元素设置,给数组的元素读写,可以通过getFilePointer 获取指针位置,他是IO包的成员,因为他具备读写的功能,通过指针对数组中的元素进行操作,通过seek改变指针的位置。
需要思考的是如果能完成读写应该有读写方法,其原理是内部封装了字节输入输出流。操作数据必然是流。封装的是byte数组,所以只能是字节流。
通过构造函数可以看出该类只能操作文件。不能操作别的。他的设备只能是硬盘上的文件,操作文件有模式,模式是读写只读只写等。
write只能在文件上写最低的8位查表的结果,表示GDK 或者utf8 的表,比如你写258 结果就是2的GDK 的对应数。
如果模式是R就是只读不会创建文件,会去读取一个已经存在的文件,如果该文件不存在则出现异常,如果模式是RW 的话,操作的文件不存在会自动创建,存在不会复制。
实例:在JAVA 中写入一些人的信息然后输入到一个文件里
package 随机访问文件类RandomAcessFile;
import java.io.*;
public class RandomAccesFileDemo {
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args) throws IOException {
writeFile_2();
readFile();
}
public static void writeFile_2() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.seek(8*0);
raf.write("周期".getBytes());
raf.write(103);
raf.close();
}
public static void readFile() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","r");
//调整对象中的//王5在第八个字节那边开始的
//raf.seek(8);输出的是//name = 王五
// age:99
//跳过指定的字节数
// raf.skipBytes(8);//和seek(8)一个效果但是不能往后跳,只能网前跳
byte [] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
System.out.println("name = "+name);
int age = raf.readInt();
sop("age:"+age);
raf.close();
}
public static void writeFile() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.write("李四".getBytes());
raf.writeInt(97);
raf.write("王五".getBytes());
raf.writeInt(99);;
raf.close();
}
}
输出结果:
ran点txt文件存在,内容是 3个人的名字和年龄。
DataStream 类
DataStream 提供了一个为基本数据类型写入到文件或者控制台上的类,如果有基本数据类型需要写入或者从文件读取都建议用这个类
实例:写入文件,读取文件,使用自带的写入8bytes的字码表写入文件,通过使用8byte的字码表读取文件
package 基本数据类流;
import java.io.*;
public class DataStreamDemo {
public static void main(String[] args) throws IOException {
// writeData();
// readDate();
// writeUTFDemo();
//
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");//用gbk子嘛表创建一个文件
// osw.write("你好");
// osw.close();
// readUTFDemo();
}
public static void writeUTFDemo() throws IOException//用某个类写的就只能用某个类的码表读出来整个表就不能被UTF8 和GB读取
{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdate.txt"));
dos.writeUTF("你好");//提供了一个8位字节的文件写入流
dos.close();
}
public static void readUTFDemo() throws IOException//提供了一个8位字节的文件信息读取方法。
{
DataInputStream dis = new DataInputStream(new FileInputStream("utfdate.txt"));
String s = dis.readUTF();
System.out.println(s);
dis.close();
}
public static void readDate() throws IOException//读取基本数据类型的信息在一个文件中
{
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int num = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
System.out.println(num);
System.out.println(b);
System.out.println(d);
dis.close();
}
public static void writeData() throws IOException///向一个文件叫做data点txt 输入几个基本数据类型的信息
{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(234);
dos.writeBoolean(true);
dos.writeDouble(9887.543);
dos.close();
}
}
输出结果
data点txt 文件创建了内容是
乱码
utfdate.txt
文件被创建了,内容是8 字节的你好
被读取在控制台上内容是
234
true
9887.543
gbk.txt
文件被创建了,内容是4个字节的你好
java.io
类 ByteArrayInputStream
java.lang.Objectjava.io.InputStream
java.io.ByteArrayInputStream
-
所有已实现的接口:
- Closeable
public class ByteArrayInputStream extends InputStream
ByteArrayInputStream
包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read
方法要提供的下一个字节。
关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
-
从以下版本开始:
- JDK1.0 另请参见:
-
StringBufferInputStream
构造方法摘要 | |
---|---|
ByteArrayInputStream(byte[] buf) 创建一个 ByteArrayInputStream ,使用 buf 作为其缓冲区数组。 | |
ByteArrayInputStream(byte[] buf, int offset, int length) 创建 ByteArrayInputStream ,使用 buf 作为其缓冲区数组。 |
构造方法中的byte数组没有调用底层资源,所以关闭这个流是无效的,也不会产生异常,因为源是个数组,数组放到一个缓冲区内,缓冲区能够自动变大其构造不需要目的文件其实也有目的就是在对象的内部,就是那个可变长度的字节数组。
ByteArrayInputStream:在构造的时候需要接受数据源,而且数据源是一个字节数组,
ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
因为这两个对象都操作的是数组,并没有使用系统资源,所以不用进行close关闭。
在流规律分析的时候分析过源头设备和目的设备
源头设备: 键盘 System.in,硬盘FileStream 内存ArrayStream这个源就是内存就是ByteArrayOutputStream()
目的设备
控制台 System.out,硬盘FileStream,内存ArrayStream
优势是用流的思想去操作数组,有读有写,不用判断数组长度,非常简单。 相似的还有charArrayReader/writer 和字符操作StringReader/writer。
字符编码
字符流的出现是为了方便操作字符,更重要的是加入了编码转换,通过子类转换流来完成的,比如InputStreamReader/Writer 把字节流转换为字符流,PrintReader 和PrintWriter
也使用了编码表。编码表是用二进制的数字的排列组合来对应各种文字和符号。常见的编码表是ASCII 美国标准信息交换吗,用一个字节的7位可以表示,ISO8859-1是欧洲的编码表,是8位的码表,用一个字节的8位表示。中国是GB2312 的中文编码表,后来升级为GBK涵盖两万多个汉字啥的并且继续在扩容中将来也许会把所有的文字包括藏文都弄进去。中国为了避免重复中国的两个自己的高位都是1中国的码表兼容ASCII码表。因为中文有拉丁拼音。
后来发明了Unicode ,国际码表两个字节代表一个文字,16个二进制的数能排列6535 个数字进行组合对于一个字节能进去的用了两个字节就比较浪费所以出现了UTF-8就是能用一个1字节能装下的用1个能用2 个用两个能用三个用三个,每个UTF-8 都有标志一下子就能看出来UTF-8 现在是世界通用,UTF-8 和 GBK 都能识别中文,但是数字不同。UTF8 也不能识别全部文字所以很多时候要用不同的码表。
实例:使用UTF-8和GBK编码表编写文件以及读取
package 编码表和数据流;
import java.io.*;
public class EncodeStream {
public static void main(String[] args) throws IOException {
//writeText();
readText();
}
public static void readText() throws IOException
{
InputStreamReader isr = new InputStreamReader(new FileInputStream("utf.txt"),"GBK");
char[] buf = new char[10];
int len = isr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
isr.close();
}
public static void writeText() throws IOException
{
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"utf-8");
osw.write("你好");
osw.close();
}
}
输出结果:
浣犲ソ
原因是 utf 写出的数据是用3 个字节去编码你三个字节编码好总共6个字节,读取的时候使用的是GBK编码表,GBK编码表的话两个字节是一个中文,utf的你 的那三个字节的前两个字节被读取然后跟着gbk去对比出现了一个 浣 字对应,之后依次查表给出以上的文字。
如果客户端发给服务器端的中文信息是用utf8或者GBK 编码的而服务器端应用的都是ISO8859-1的编码表就会出现??? 问号,为了解决这个问题我们需要先把问号转变成了字节码,然后再用字节码对照ISO8859 和GBK 去解码最后获得对应的正确的汉
实例2 从问号变成汉字 使用的是ISO8859和GBK 码表
package 编码表和数据流;
import java.io.UnsupportedEncodingException;
import java.util.*;
public class EncodeDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "你好";
byte[] b1 = s.getBytes("GBK");
System.out.println(Arrays.toString(b1));//吧数组变成字符串
String s1 = new String(b1,"ISO8859-1");//通过ISO8859 去解码该数组结果出现??? 因为iso的码表找不到该数组对应的符号
System.out.println("s1="+s1);
byte[] b2= s1.getBytes("ISO8859-1");//把问号们放在iso中解码,得出相应的数组,
System.out.println(Arrays.toString(b2));//把数组转变为字符串
String s2 = new String(b2,"gbk");//吧字符串用gbk去解码
System.out.println("s2="+s2);//输出该字符串对应的汉字就是你好
}
}
输出结果是
[-60, -29, -70, -61]
s1=????
[-60, -29, -70, -61]
s2=你好
图片复制解密
我一直试图去复制一个图片但是就是复制不出来我的代码如下
package CopyText;
import java.io.*;
public class 复制图片 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("a.jpg");
FileOutputStream fos = new FileOutputStream("ac.jpg");
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf))!= -1)
{
fos.write(buf, 0, len);
fos.flush();
}
fis.close();
fos.close();
}
}
输出结果
ac点jpg完美复制
注意点,这个图片所在的地方是E:\eclips 安装\IO,而我们的这个package的地点必须在E:\eclips 安装\IO 中的IO包里才行不然不行。
所以我每次都复制不出来因为很多次文件不在这个包中,此外,Stream 是有flush 的,outputStream 必须flush 才行。
注意点2, 方法不是只有这一个,还有一个trycatch 的也行就是麻烦我懒得写,但是结果是一样的好
package FileOutputStream;
import java.io.*;
public class CopyPic {
public static void main(String[] args) throws IOException{
FileInputStream fis = null;
FileOutputStream fos = null;
try{
fos = new FileOutputStream("ac.jpg");// 我这个就打开看不到 咋弄的
fis = new FileInputStream("a.jpg");
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf))!= -1)
{
fos.write(buf, 0, len);
fos.flush();
}
}
catch(IOException e)
{
System.out.println(e.toString()+"复制文件失败");
}
finally{
try{
if(fis != null)
fis.close();
}
catch(IOException e)
{
System.out.println("读关闭失败");
}
try{
if(fos != null)
fos.close();
}
catch(IOException e)
{
System.out.println("写入关闭失败");
}
}
}
}
输出结果:
一样完美复制图片a。