package cn.itcast.dao.impl;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import cn.itcast.dao.UserDao;
import cn.itcast.pojo.User;
/**
* 这是用户操作的具体实现类(IO版)
*
* @author 风清扬
* @version V1.1
*/
public class UserDaoImpl implements UserDao {
// 为了保证文件一加载就创建
private static File file = new File("user.txt");
static {
try {
file.createNewFile();
} catch (IOException e) {
System.out.println("创建文件失败");
// e.printStackTrace();
}
}
@Override
public boolean isLogin(String username, String password) {
boolean flag = false;
BufferedReader br = null;
try {
// br = new BufferedReader(new FileReader("user.txt"));
br = new BufferedReader(new FileReader(file));
String line = null;
while ((line = br.readLine()) != null) {
// 用户名=密码
String[] datas = line.split("=");
if (datas[0].equals(username) && datas[1].equals(password)) {
flag = true;
break;
}
}
} catch (FileNotFoundException e) {
System.out.println("用户登录找不到信息所在的文件");
// e.printStackTrace();
} catch (IOException e) {
System.out.println("用户登录失败");
// e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
System.out.println("用户登录释放资源失败");
// e.printStackTrace();
}
}
}
return flag;
}
@Override
public void regist(User user) {
/*
* 为了让注册的数据能够有一定的规则,我就自己定义了一个规则: 用户名=密码
*/
BufferedWriter bw = null;
try {
// bw = new BufferedWriter(new FileWriter("user.txt"));
// bw = new BufferedWriter(new FileWriter(file));
// 为了保证数据是追加写入,必须加true
bw = new BufferedWriter(new FileWriter(file, true));
bw.write(user.getUsername() + "=" + user.getPassword());
bw.newLine();
bw.flush();
} catch (IOException e) {
System.out.println("用户注册失败");
// e.printStackTrace();
} finally {
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
System.out.println("用户注册释放资源失败");
// e.printStackTrace();
}
}
}
}
}
操作基本数据类型
(操作基本数据的流)
DataInputStream
DataOutputStream
内存操作流
操作字节数组
ByteArrayInputStream
ByteArrayOutputStream
操作字符数组
CharArrayReader
CharArrayWrite
操作字符串
StringReader
StringWriter
内存操作流一般用于处理临时信息,因为临时信息不需要保存,使用后就可以删除。
2:以第一个举例即可
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("helloworld".getBytes());
baos.close();
byte[] bys = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bys);
int by = 0;
while ((by = bais.read()) != -1) {
System.out.println((char) by);
}
baos.close();
bais.close();
最后的close()可以不写,通过看源码可以知道这里什么都没有做。
打印流概述
:只有写,没有读。
字节流打印流
字符打印流
打印流特点
只能操作目的地,不能操作数据源。
可以操作任意类型的数据。
如果启动了自动刷新,能够自动刷新。
可以操作文件的流
打印流复制文本文件
System类中的字段:in,out。(标准的输入输出流)
它们各代表了系统标准的输入和输出设备。
默认输入设备是键盘,输出设备是显示器。
System.in的类型是InputStream.
(字节流)System.out的类型是PrintStream(字符打印流)
是OutputStream的子类FilterOutputStream 的子类.
RandomAccessFile概述
RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。支持对随机访问文件的读取和写入。【该类的构造方法的第二个参数就是读写文件的模式,一共有四种,用得最多的是rw】utf对应汉字的是3个字节,想读取就可以读取那个位置,是通过设置指针位置来实现的。
SequenceInputStream概述
(合并流)SequenceInputStream类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。
SequenceInputStream的构造方法
SequenceInputStream(InputStream s1, InputStream s2)
SequenceInputStream(Enumeration<? extends InputStream> e)
把多个文件的内容写入到一个文本文件
合并流的一个构造可以合并两个文件,有一个构造可以合并多个文件,但是需要注意的是,该多个流的合并需要用到vector集合的方法,所以就得创建该集合。
序列化流
ObjectOutputStream
(写)反序列化流
ObjectInputStream
(读)序列化操作问题
为什么要实现序列化?
如何实现序列化?
序列化数据后,再次修改类文件,读取数据会出问题,如何解决呢?
使用transient关键字声明不需要序列化的成员变量
对象序列化是将对象状态转换为可保持或传输的过程。一般的格式是与平台无关的二进制流,可以将这种二进制流持久保存在磁盘上,也可以通过网络将这种二进制流传输到另一个网络结点。
对象反序列化,是指把这种二进制流数据还原成对象。
Properties概述
Properties作为Map集合的使用
,(但是不能有泛型)Properties的特殊功能
public Object setProperty(String key,String value)
【添加元素】public String getProperty(String key)
【获取元素】public Set<String> stringPropertyNames()
【获取所有键的集合】Properties和IO流的结合使用
public void load(Reader reader)
【把文件的数据读取到集合中】public void store(Writer writer,String comments)
【把集合中的数据存储到文件】注意这里的集合只能是Priperties.这个文件的数据也必须是键值对形式。该集合可以应用于单机游戏状态的存贮。
NIO其实就是新IO的意思。
JDK4出现NIO。新IO和传统的IO有相同的目的,都是用于进行输入输出的,但新IO使用了不同的方式来处理输入输出,采用内存映射文件的方式,将文件或者文件的一段区域映射到内存中,就可以像访问内存一样的来访问文件了,这种方式效率比旧IO要高很多,但是目前好多地方我们看到的还是旧IO的引用,所以我们仍以旧IO为主,知道NIO即可。Buffer(缓冲),Channer(通道)
JDK7要了解的新IO类
Path:与平台无关的路径。
Paths:包含了返回Path的静态方法。
public static Path get(URI uri):根据给定的URI来确定文件路径。
Files:操作文件的工具类。提供了大量的方法,简单了解如下方法
public static long copy(Path source, OutputStream out) :复制文件
public static Path write(Path path, Iterable<? extends CharSequence> lines, Charset cs, OpenOption... options):
把集合的数据写到文件。
//复制文件
Files.copy(Paths.get("Demo.java"), newFileOutputStream("Copy.Java"));
//把集合中的数据写到文件
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
Files.write(Paths.get("list.txt"), list, Charset.forName("gbk"));
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();
package cn.itcast_09;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
/*
* nio包在JDK4出现,提供了IO流的操作效率。但是目前还不是大范围的使用。
* 有空的话了解下,有问题再问我。
* JDK7的之后的nio:
* Path:路径
* Paths:有一个静态方法返回一个路径
* public static Path get(URI uri)
* Files:提供了静态方法供我们使用
* public static long copy(Path source,OutputStream out):复制文件
* public static Path write(Path path,Iterable<? extends CharSequence> lines,Charset cs,OpenOption... options)
*/
public class NIODemo {
public static void main(String[] args) throws IOException {
// public static long copy(Path source,OutputStream out)
// Files.copy(Paths.get("ByteArrayStreamDemo.java"), new
// FileOutputStream(
// "Copy.java"));
ArrayList<String> array = new ArrayList<String>();
array.add("hello");
array.add("world");
array.add("java");
Files.write(Paths.get("array.txt"), array, Charset.forName("GBK"));
}
}
package cn.itcast_08;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Properties;
/*
* 这里的集合必须是Properties集合:
* public void load(Reader reader):把文件中的数据读取到集合中
* public void store(Writer writer,String comments):把集合中的数据存储到文件
* 单机版游戏:
* 进度保存和加载。
* 三国群英传,三国志,仙剑奇侠传...
*
* 吕布=1
* 方天画戟=1
*/
public class PropertiesDemo3 {
public static void main(String[] args) throws IOException {
// myLoad();
myStore();
}
private static void myStore() throws IOException {
// 创建集合对象
Properties prop = new Properties();
prop.setProperty("林青霞", "27");
prop.setProperty("武鑫", "30");
prop.setProperty("刘晓曲", "18");
//public void store(Writer writer,String comments):把集合中的数据存储到文件
Writer w = new FileWriter("name.txt");
prop.store(w, "helloworld");
w.close();
}
private static void myLoad() throws IOException {
Properties prop = new Properties();
// public void load(Reader reader):把文件中的数据读取到集合中
// 注意:这个文件的数据必须是键值对形式
Reader r = new FileReader("prop.txt");
prop.load(r);
r.close();
System.out.println("prop:" + prop);
}
}
package cn.itcast_08;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Properties;
/*
* 我有一个猜数字小游戏的程序,请写一个程序实现在测试类中只能用5次,超过5次提示:游戏试玩已结束,请付费。
*/
public class PropertiesTest2 {
public static void main(String[] args) throws IOException {
// 读取某个地方的数据,如果次数不大于5,可以继续玩。否则就提示"游戏试玩已结束,请付费。"
// 创建一个文件
// File file = new File("count.txt");
// if (!file.exists()) {
// file.createNewFile();
// }
// 把数据加载到集合中
Properties prop = new Properties();
Reader r = new FileReader("count.txt");
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++;
prop.setProperty("count", String.valueOf(number));
Writer w = new FileWriter("count.txt");
prop.store(w, null);
w.close();
GuessNumber.start();
}
}
}
线程休眠
public static void sleep(long millis)
【以毫秒为单位】
线程加入
【等待该线程终止,别的线程才可以抢】
public final void join()
线程礼让
【暂停当前正在执行的线程对象,并执行其他线程,它可以让多个线程的执行更和谐,但是不能保证一人一次】
public static void yield()
后台线程
【将该线程记为守护线程或用户线程,当正在运行的线程是守护线程时,java虚拟机退出,该方法必须在启动线程前调用】
public final void setDaemon(boolean on)
中断线程
public final void stop()
【让线程停止,已经过时了,不过还可以用,太过暴力,直接停止了,后面的代码就不能运行】
public void interrupt()
【中断线程,把线程的状态终止,并抛出一个异常,好让的代码运行】
实现接口方式的好处
可以避免由于Java单继承带来的局限性。
适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离,较好的体现了面向对象的设计思想。
相同的票出现多次:
CPU的一次操作必须是原子性的
还出现了负数的票:
随机性和延迟导致的
package cn.itcast_08;
public class SellTicket implements Runnable {
// 定义100张票
private int tickets = 100;
@Override
// public void run() {
// while (true) {
// // t1,t2,t3三个线程
// // 这一次的tickets = 100;
// if (tickets > 0) {
// // 为了模拟更真实的场景,我们稍作休息
// try {
// Thread.sleep(100); // t1就稍作休息,t2就稍作休息
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// System.out.println(Thread.currentThread().getName() + "正在出售第"
// + (tickets--) + "张票");
// // 理想状态:
// // 窗口1正在出售第100张票
// // 窗口2正在出售第99张票
// // 但是呢?
// // CPU的每一次执行必须是一个原子性(最简单基本的)的操作。
// // 先记录以前的值
// // 接着把ticket--
// // 然后输出以前的值(t2来了)
// // ticket的值就变成了99
// // 窗口1正在出售第100张票
// // 窗口2正在出售第100张票
//
// }
// }
// }
@Override
public void run() {
while (true) {
// t1,t2,t3三个线程
// 这一次的tickets = 1;
if (tickets > 0) {
// 为了模拟更真实的场景,我们稍作休息
try {
Thread.sleep(100); //t1进来了并休息,t2进来了并休息,t3进来了并休息,
} catch (InterruptedException e) {
e.printStackTrace();
}System.out.println(Thread.currentThread().getName() + "正在出售第"
+ (tickets--) + "张票");
//窗口1正在出售第1张票,tickets=0
//窗口2正在出售第0张票,tickets=-1
//窗口3正在出售第-1张票,tickets=-2
}
}
}
}
首先想为什么出现问题?(也是我们判断是否有问题的标准)
是否是多线程环境
是否有共享数据
是否有多条语句操作共享数据
如何解决多线程安全问题呢?
基本思想:让程序没有安全问题的环境。
怎么实现呢?
把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。
同步代码块
格式:
synchronized(对象){需要同步的代码;}
同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。(这个对象要形成唯一的一把”锁”,定义成成员变量为佳)
package cn.itcast_10;
public class SellTicket implements Runnable {
// 定义100张票
private int tickets = 100;
// 定义同一把锁
private Object obj = new Object();
@Override
public void run() {
while (true) {
// t1,t2,t3都能走到这里
// 假设t1抢到CPU的执行权,t1就要进来
// 假设t2抢到CPU的执行权,t2就要进来,发现门是关着的,进不去。所以就等着。
// 门(开,关)
synchronized (obj) { // 发现这里的代码将来是会被锁上的,所以t1进来后,就锁了。(关)
if (tickets > 0) {
try {
Thread.sleep(100); // t1就睡眠了
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票 ");
//窗口1正在出售第100张票
}
} //t1就出来可,然后就开门。(开)
}
}
}
package cn.itcast_10;
/*
* 举例:
* 火车上厕所。
* 同步的特点:
* 前提:
* 多个线程
* 解决问题的时候要注意:
* 多个线程使用的是同一个锁对象
* 同步的好处
* 同步的出现解决了多线程的安全问题。
* 同步的弊端
* 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
*/
public class SellTicketDemo {
public static void main(String[] args) {
// 创建资源对象
SellTicket st = new SellTicket();
// 创建三个线程对象
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
}
如何把一个线程不安全的集合类变成一个线程安全的集合类
用Collections工具类的方法即可。
死锁是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象
原文:http://www.cnblogs.com/yc74/p/5493398.html