打印流
* 打印流
* 字节打印流 PrintStream
* 字符打印流 PrintWriter
*
* 打印流的特点:
* A:只有写数据,没有读数据。只能操作目的地,不能操作数据源
* B:可以操作任意类型的数据
* print()
* println()
* C:如果启动了自动刷新,能够自动刷新
* PrintWrite bw = new PrintWriter(new FileWriter/FileOutPutStream("pw2.txt"),true)
* 调用println()的方法才可以
* 这个时候不仅仅自动刷新了,还实现了数据的换行
* println()
* 等价于
* bw.write();
* bw.newLine();
* bw.flush();
* D:该流是可以直接操作文本文件的
* 哪些对象是可以直接操作文本文件的呢?
* FileInputStream
* FileOutputStream
* FileReader
* FileWriter
* PrintWriter
* printStream
* 看API,查流对象的构造方法,如果同时有File类型和String类型的参数,一般来说就是可以直接操作文件的
*
* 流:
* 基本流:就是能够直接读写文件的
* 高级流:在基本流操作基础上提供了一些其他的功能
序列化流和反序列化流
* 序列化:把对象按照流一样的方式存入文本文件或者在网络中传输。对象----》流数据(ObjectOutputStream)
* 反序列化:把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据---》对象(ObjectInputStream)
*
* NotSerializableException:未序列化异常
* 类通过实现 java.io.Serializable
* 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
* 该接口居然没有任何方法,类似于这种没有方法的接口被称为标记接口。
*
* local class incompatible:
* stream classdesc serialVersionUID = -8036188228921520309,
* local class serialVersionUID = -3432617418350035952
*
* 为什么有问题呢?
* Person类实现了序列化接口,那么它本身也应该有一个标记值。
* 这个标记值假设是100。
* 开始的时候:
* Person.class -- id=100
* write数据:oos.txt -- id = 100
* read数据:oos.txt -- id = 100
* 现在:
* Person.class -- id = 200
* write数据:oos.txt -- id =100
* read数据:oos.txt -- id = 100
* 我们实际开发中,可能需要使用以前写过的数据,不能重新写入。怎么办呢?
* 回想一下原因是因为他们的id值不匹配。
* 每次修改java文件的内容的时候,class文件的id值都会发生变化
* 而读取文件的时候,会和class文件中的id值进行匹配。所以就会出问题。
* 但是呢,如果我有办法让这个id值在java文件中是一个固定的值,这样,你修改文件的时候,
* 这个id值就不会发生改变,现在的关键是我如何知道这个id值如何表示呢?
* 不用担心,你不用记住也没关系,鼠标点击即可。
* 你难道没有看到黄色警告线吗?
*
* 我们要知道的是:
* 看到类实现序列化接口的时候,要想解决黄色警告线问题,就可以自动产生一个序列化id值。
* 而且产生这个值以后,我们对类进行任何改动,它读取以前的数据是没问题的。
*
* 注意:
* 我一个类中可能有很多的成员变量,有些我不想进行序列化,请问该怎么办呢
* 使用transient关键字声明不需要序列化的成员变量
Properties集合
* Properties:属性集合类,是一个可以和IO流相结合使用的集合类。
* Properties可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
* Properties是Hashtable的子类,说明是一个Map集合
* Properties属性集合类的特有功能:
* public Object setProperty(String key, String value):添加元素
* public String getProperty(String key):获取元素
* public Set<String> stringPropertyNames():获取所有键的集合
*
* 这里的集合必须是Properties集合
* public void load(Reader reader):把文件中的数据读取到集合中
* 注意:这个文件的数据必须是键值对形式
* public void store(Writer writer,String comments):把集合中的数据存储到文件
commons-IO
Properties、序列化流、打印流大总结
1:登录注册IO版本案例(掌握)
cn.itcast.pojo User
class User {//【代码实现】
//成员变量
private String username;
private String password;
//构造方法
public User(){}//无参构造
public User(String username,String password){ //满带参构造
this.username = username;
this.password = password;
}
//成员方法setXxx()/getXxx()
public void setUsername(String username){
this.username = username;
}
public String getUsername(){
return username;
}
public void setPassword(String password){
this.password = password;
}
public String getPassword(){
return password;
}
}
cn.itcast.dao UserDao
public interface UserDao {//【代码实现】
public abstract boolean isLogin(String username,String password);
public abstract void regist(User user);
}
cn.itcast.dao.impl UserDaoImpl(实现我不管)
public class UserDaoImpl implements UserDao {//【代码实现】
private static File file = new File("user.txt");
static {
try {
file.createNewFile();
} catch (IOException e) {
System.out.println("用户信息文件创建失败");
}
}
@Override
public boolean isLogin(String username, String password) {
BufferedReader br = null;
boolean isRight = false;
try {
br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
String[] arr = line.split("=");
if (arr[0].equals(username) && arr[1].equals(password)) {
isRight = true;
break;
}
}
} catch (FileNotFoundException e) {
System.out.println("用户信息文件找不到,登录失败");
} catch (IOException e) {
System.out.println("用户登录失败");
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
System.out.println("用户登录信息释放资源关闭失败");
}
}
}
return isRight;
}
@Override
public void regist(User user) {
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(file, true));
bw.write(user.getUsername() + "=" + user.getPassword());
bw.newLine();
bw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("用户注册信息失败");
} finally {
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("注册信息释放资源失败");
}
}
}
}
}
cn.itcast.game GuessNumber
public class GuessNumber{//【代码实现】
public static void start(){
int number = (int)(Math.random()*100+1);
int count = 0;
while(true){
Scanner sc = new Scanner(System.in);
System.out.println("请输入你猜的数字:");
int guessNumber = sc.nextInt();
count++;
if(number > guessNumber){
System.out.println("你猜的数字"+guessNumber+"小了");
}else if(number<guessNumber){
System.out.println("你猜的数字"+guessNumber+"大了");
}else{
System.out.println("恭喜你猜了"+count+"次猜中了");
break;
}
}
}
}
cn.itcast.test UserTest
public class UserTest {//【代码实现】
public static void main(String[] args) {
while (true) {
// 欢迎界面,给出选择项
System.out.println("------o------欢迎光临------------");
System.out.println("1.登录");
System.out.println("2.注册");
System.out.println("3.退出");
System.out.println("------------------------------");
Scanner sc = new Scanner(System.in);
// 键盘录入选择,根据选择做不同的操作
System.out.println("请输入你的选择(1-3):");
// 为了后面的录入信息的方便,我所有的数据录入全部用字符接收
String choice = sc.nextLine();
// switch多个地方要使用,我就定义到外面
UserDao ud = new UserDaoImpl();
switch (choice) {
case "1":
System.out.println("------------登录界面------------");
System.out.println("请输入用户名:");
String username = sc.nextLine();
System.out.println("请输入密码:");
String password = sc.nextLine();
// UserDao ud = new UserDaoImpl();
boolean success = ud.isLogin(username, password);
if (success) {
System.out.println("登陆成功,可以开始玩猜数字游戏了");
System.out.println("你玩吗?y/n");
while (true) {
String s = sc.nextLine();
if ("y".equalsIgnoreCase(s)) {
GuessNumber.start();
System.out.println("你还玩吗?y/n");
} else {
break;
}
}
System.out.println("谢谢使用,欢迎下次再来!");
System.exit(0);
// break;//这里写break,结束的是switch
} else {
System.out.println("用户名或密码错误,登陆失败");
}
break;
case "2":
System.out.println("------------注册界面------------");
System.out.println("请输入用户名:");
String newUsername = sc.nextLine();
System.out.println("请输入密码:");
String newPassword = sc.nextLine();
// 把用户名和密码封装到对象中
User user = new User();
user.setUsername(newUsername);
user.setPassword(newPassword);
// 调用注册功能
// 多态
// UserDao ud = new UserDaoImpl();
// 具体类使用
// UserDao use = new UserDaoImpl();
ud.regist(user);
System.out.println("注册成功");
break;
case "3":
default:
System.out.println("谢谢使用,再见!");
System.exit(0);
break;
}
}
}
}
2:数据操作流(操作基本类型数据的流)(理解)
(1)可以操作基本类型的数据【byte,short,char,boolean,int,long,double,float】
(2)流对象名称
DataInputStream readXxx();
DataOutputStream writeXxx();
3:内存操作流(理解)
(1)有些时候我们操作完毕后,未必需要产生一个文件,就可以使用内存操作流。
(2)三种
A:ByteArrayInputStream,ByteArrayOutputStream 字节数组操作流【参数是字节数组】
B:CharArrayReader,CharArrayWriter 字符数组操作流【参数是字符数组】
C:StringReader,StringWriter 字符串数组操作流【参数是字符串数组】
4:打印流(掌握)
(1)字节打印流【PrintStream】,字符打印流【PrintWriter】
(2)特点:
A:只操作目的地,不操作数据源
B:可以操作任意类型的数据
C:如果启用了自动刷新,在调用println()方法的时候,能够换行并刷新
D:可以直接操作文件
问题:哪些流可以直接操作文件呢?
看API,如果其构造方法能够同时接收File和String类型的参数,一般都是可以直接操作文件的
(3)复制文本文件
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
PrintWriter pw = new PrintWriter(new FileWriter("b.txt"),true);
String line = null;
while((line=br.readLine())!=null) {
pw.println(line);
}
pw.close();
br.close();
5:标准输入输出流(理解)
(1)System类下面有这样的两个字段
public static final InputStream in; 标准输入流 InputStream is = System.in;
public static final OutputStream out; 标准输出流 OutputStream os = System.out;
(2)三种键盘录入方式
A:main方法的args接收参数
B:System.in通过BufferedReader进行包装
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
C:Scanner
Scanner sc = new Scanner(System.in);
(3)输出语句的原理和如何使用字符流输出数据
A:原理
System.out.println("helloworld");
等价于
PrintStream ps = System.out;
ps.println("helloworld");
B:把System.out用字符缓冲流包装一下使用
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
6:随机访问流(理解)【RandomAccessFile】
(1)可以按照文件指针的位置写数据和读数据。
(2)案例:
A:写数据 write()
B:读数据 read()
C:获取和改变文件指针的位置 long getFilePointer()和void seek(long pos)
7:合并流(理解)
(1)把多个输入流的数据写到一个输出流中。
(2)构造方法:
A:SequenceInputStream(InputStream s1, InputStream s2)
B:SequenceInputStream(Enumeration<? extends InputStream> e)
案例:
* public SequenceInputStream(Enumeration<? extends InputStream> e)
* 通过简单的回顾我们知道了Enumeration是Vector中的一个方法的返回值类型。
* Enumeration<E> elements()
*
* Vector<InputStream> v = new Vector<InputStream>();
* InputStream is1 = new FileInputStream("copy2.java");
* ...
* v.addElement(is1);
* ...
* Enumeration<InputStream> en= v.elements();
* SequenceInputStream sis = new SequenceInputStream(en);
* BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("多合并.txt"));
* byte[] bytes = new byte[4096];
* int by;
* while((by = sis.read(bytes))!=-1){
* bos.write(bytes, 0, by);
* bos.flush();
* }
* bos.close();
* sis.close();
8:序列化流(理解)【ObjectInputStream&&ObjectOutputStream】
(1)可以把对象写入文本文件或者在网络中传输
(2)如何实现序列化呢?
让被序列化的对象所属类实现序列化接口。
该接口是一个标记接口。没有功能需要实现。
(3)注意问题:
把数据写到文件后,如果再去修改类会产生一个问题。
如何解决该问题呢?
在类文件中,给出一个固定的序列化id值。
而且,这样也可以解决黄色警告线问题
如果对象中的某个属性不想被序列化,加关键字transient修饰,该对象就不能被序列化了。
(4)面试题:
什么是序列化? 将对象------转换成-----》流数据
如何实现序列化? 让被序列化的对象所属类去实现序列化接口
什么是反序列化? 将流数据------转换成-----》对象
9:Properties(理解)
(1)是一个集合类,Hashtable的子类
(2)特有功能
A:public Object setProperty(String key,String value):添加元素
B:public String getProperty(String key):根据键获取值
C:public Set<String> stringPropertyNames():获取所有的键
案例:
//创建集合对象
Properties prop = new Properties();
//添加元素
prop.setProperty("张三", "30");
prop.setProperty("李四", "40");
prop.setProperty("王五", "50");
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
String value = prop.getProperty(key);
System.out.println(key+"-----"+value);
}
(3)和IO流结合的方法
把键值对形式的文本文件内容加载到集合中
public void load(Reader reader)
public void load(InputStream inStream)
把集合中的数据存储到文本文件中
public void store(Writer writer,String comments)
public void store(OutputStream out,String comments)
(4)案例:
A:根据给定的文件判断是否有键为"lisi"的,如果有就修改其值为100
//A:把文件中的数据加载到集合中
//创建集合对象
Properties prop = new Properties();
//创建字符输入流对象
Reader r = new FileReader("prop.txt");
//将文件中的数据加载到集合
prop.load(r);
//释放资源
r.close();
//B:遍历集合,获取得到每一个键
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
//C:判断键是否有“lisi”的,如果有就修改其值为“100”
if("lisi".equals(key)){
prop.setProperty(key, "100");
}
}
//D:把集合中的数据重新存储到文件中
Writer w = new FileWriter("prop.txt");
prop.store(w, null);
w.close();
B:写一个程序实现控制猜数字小游戏程序不能玩超过5次
// 把键值对形式的文本文件内容加载到集合中
Reader r = new FileReader("count.txt");
Properties prop = new Properties();
prop.load(r);
r.close();
String value = prop.getProperty("count");
int number = Integer.parseInt(value);
if(number>5){
System.out.println("游戏试玩已结束,请付费。");
System.exit(0);
}else{
number++;
GuessNumber.start();
//把集合中的数据存储到文本文件中
prop.setProperty("count", String.valueOf(number));
Writer w = new FileWriter("count.txt");
prop.store(w, null);
w.close();
}
10:NIO(了解)
(1)JDK4出现的NIO,对以前的IO操作进行了优化,提供了效率。但是大部分我们看到的还是以前的IO
(2)JDK7的NIO的使用
Path:路径
Paths:通过静态方法返回一个路径
Files:提供了常见的功能
复制文本文件
把集合中的数据写到文本文件