第一章,文件及IO流
文件:计算机以硬盘,光盘,移动存储设备等为载体的储存在计算机上的信息集合,通常有扩展名。
文件系统(文件+目录+符合链接):Linux和Unix操作系统只有一个根目录,Windows系统有多个。
文件路径:绝对路径+相对路径;
File类:java.io包中提供对文件进行处理的接口和类,File类代表与平台无关的文件和目录,File类可以对文件,目录及其属性进行管理和访问,是java.io包中唯一磁盘文件本身的对象,通过调用File类中的方法实现创建,删除,重命名文件等操作。
使用File类创建一个文件对象。
new File(String pathname);://给定路径名字符串转换为抽象路径名来创建一个新的File实例。File file=new File("F:\\1.txt")
new File(String patrent,String child);//根据定义的父路径和子路径字符串(包含文件名)创建,File file=new File("F:\\","1.txt")
new File(File f,String child);//根据定义的父路径对象和子路径字符串创建,File file = new File(f,"1.txt");
访问文件名或路径 | String getName() | 返回File对象所表示的文件名和目录的路径 |
String getPath() | 返回File对象所对应的路径名 | |
File getAbsoluteFile() | 返回File对象的绝对路径文件 | |
String getAbsolutePath() | 返回File对象的对应的绝对路径名 | |
String getParent() | 返回File对应的目录的父目录 | |
文件检测 | boolean exists() | 判断File对象所对应的文件或目录是否存在 |
boolean canWrite() | 判断File对象所对应的文件或目录是否可写 | |
boolean canRear() | 判断File对象所对应的文件或目录是否可读 | |
boolean isDirectory() | 判断File对象是否为一个目录 | |
boolean isFile() | 判断File对象是否为一个文件 | |
boolean isAbsolute() | 判断File对象是否采用绝对路径 | |
文件信息 | long length() | 返回File对象所对应文件的长度(byte) |
long lastModified() | 返回File对象的最后一次被修改的时间 | |
文件操作 | boolean carateNewFlie() | 检查文件是否存在,不存在时新建一个文件 |
boolean delete() | 删除File对象所对应的文件或目录 | |
目录操作 | boolean mkdir() | 创建一个File对象所对应的路径 |
String [] list() | 列出File对象所有的子文件和路径名 | |
File [] listFile() | 列出File对象所有的子目录和路径 | |
static File[] listRoots() | 列出系统所有的根路径 | |
文件检测 | isHidden | 判断文件是否为隐藏文件 |
FilenameFilter接口:是一个文件过滤器接口,该接口只提供一个accept(File dir,String name)方法,该方法的返回值类型为boolean型,可以对文件进行过滤,File的list()方法可以接受FileNameFiler类型的参数"."代表当前目录,获取相对路径的父路径可能会出错,要使用getAbsolutePath().getParent()返回。当使用createNewFile()创建新文件时 ,可能回引发IOException异常,因此需要try……catch语句进行异常处理。路径分割符需要使用“\\”.
String[] list(FilenameFilter filter)//返回File对象所对应的目录中满足指定过滤条件的文件名和子目录名;
File [] listFiles(FilenameFilter fifter)//返回File对象所对应的目录中满足指定过滤条件的文件和子目录。
String [] filterFileNames = file.list(new FilenameFilter(){
public boolean accept(File dir,String name){
return (name.endsWith(".mp3")||name.endsWith(".text"));
}
});//创建FileNameFilter类型的匿名内部类直接实现该接口中的accept()方法,并作为参数传入到list()方法中。
IO流:Java的IO流是是实现数据输入(Input)和数据输出(Output)的基础。可以对数据实现读写操作。流(Stream)的优势在于使用统一的方式对数据进行操作或传递,简化了代码操作。流提供了一条通道程序,可以使用这条通道把源中的字节序列送到目的地,
在Java中“数据源”可以是一个磁盘文件,一个网络套接字,甚至一个网络文件。
流的分类:
按照流向来分(从程序运行所作的内存角度来划分):输入流(只能读取数据(数据源),而不能写入数据)+输出流(只能写入数据(数据源),不能读取数据)。
按照流所操作的基本数据单元来分:字节流(所操作的基本数据单元是8位(byte),无论输入输出都直接对字节进行处理)+字符流(所操作的基本数据单元是16位的字符(Unicode),无论输入输出都直接对字符进行处理)。
按照流的角色来分:节点流(用于从/向一个特定的IO设备(磁盘,网络)读/写数据的流,也称低级流(Low Level Stream),节点通常指文件,内存或管道)+处理流(对一个已经存在的流进行连接或封装,通过封装后的流来实现数据的读/写功能,又称高级流)
Java中使用处理流来包装节点流是一种典型的使用模式,通过使用处理流来包装不同的节点流,消除了不同节点流实现的差异,
流的体系结构:Java的IO流都是由4个抽象基类派生的:
字节流 | 输入流:InputStream(数据的读操作) | |
输出流:OutputStream(数据的写操作) | ||
IO流 | 字符流 | 输入流:Reader(数据的读操作) |
输出流:Writer(数据的写操作) |
Java的IO流体系按照功能分类的常用流表,其中访问文件,数组,管道和字符串的流都是节点流,必须直接与指定的物理节点关联,
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
访问管道 | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter |
访问字符串 | StringReader | StringWriter | ||
缓存流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputStreamWriter | ||
对象流 | ObjectInputStream | ObjectOutputStream | ||
过滤基类 | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
打印流 | PrintStream | PrintWriter | ||
推回输入流 | PushbackInputStream | PushbackReader | ||
特殊流 | DataInputStream | DataOutputStream |
计算机中所有的数据都是以二进制的形式组织,而字节流可以处理所以二进制文件。所以字节流比字符流功能强大,在使用IO流时要注意。如果进行输入输出的内容是文本内容,则使用字符流,如果进行输入的是二进制内容,则使用字节流。计算机中的文件被分为二进制文件和文本文件,所有能被记事本正常显示打开的文件都称为文本文件,反之则称为二进制文件。
字节流:
字节流处理的基本单元是字节,其输入/输出操作都是在字节的基础上进行的,字节流的两个抽象基类InputStream和OutputStream,其他的字节流都是由这两个字节流派生的。
InputSream(字节输入流):可以从数据源以字节为单位读取数据。
abstract int read() | 读取一个字节并返回,如果遇到源的末尾,则返回-1 |
int read( byte[] b) | 将数据读入到字节数组中,并返回实际读取的字节数,当已达到流的尾端而没有可以使用的字节时,返回-1 |
int read(byte[] b,int offset,int len) | 将数据读入到字节数组中,并返回实际读取的字节数,当已达到流的尾端而没有可以使用的字节时,返回-1,len表示读取的最大字节数,offset表示数组中存放数据的开始位置。 |
int available() | 用于返回在不发生阻赛的情况下,从输入流中可以读取的字节数 |
void close() | 关闭此输入流,并释放与该流关联的所有系统资源。 |
mark(int readlimit) | 在输入流的当前位置放置一个标记,readlimit参数告知此输入流在标记失效之前允许读取的字节数 |
reset() | 将输入指针返回到当前所做的标记处 |
skip(long n) | 跳过输入流上的n个字节并返回实际跳过的字节数 |
markSupported() | 如果当前流支持mark()/reset()操作就返回true |
InputStream类是抽象类,不能直接实例化,使用其子类完成具体的功能。
InputStream | FileInputStream(文件输入流,从文件中读取二进制数据) | |
PipedInputStream(管道输入流,产生一份数据,能被写入的相应的PipedOutputStream中) | ||
FilterInputStream(过滤输入流,用于连接两个流,一个接到另个的末端,) | LineNumberInputStream | |
ByteAttayInputStream(为读取字节数组设计的流,允许内存的缓存区被当作InputStream使用) | DataInputStream | |
SequenceInputStream | BufferedInputStream | |
StringBufferInputStream | PushbackInputStream | |
ObjectInputStream(对象输入流,用于将保存在磁盘或网络中的对象读取出来) |
OutputStream(字节输出流)可以从数据源以字节为单位写入数据。
void write(int c) | 将一个字节写入到文件输入流中 |
void write(byte [] b) | 将字节数组中的数据写入到文件输出流中 |
void write(byte [] b,int offset,int len) | 将字节数组中的offset开始的len个字节写入到文件输出流中 |
void close() | 关闭此输入流,并释放与该流关联的所有系统资源 |
void flush() | 将缓存区中的字节数立即发送到流中,同时清空缓存 |
OutputStream | FileOutputStream(文件输入流,用于以二进制形式把数据写入到文件中) | |
PipedOutputStream(管道输出流,产生一份数据,能被读取到相应的PipedInputStream中) | ||
FilterOutputStream(过滤输出流,用于将一个流连接到另外一个流的末端,将两种流连接起来) | DataOutputStream | |
ByteArrayOutputStream(按照字节数组的方式向设备中写入字节流的类) | BufferedOutputStream | |
ObjectOutputStream(对象输出流,将对象保存到磁盘或在网络中传递) | PrintStream |
字节流中文件输入/输出流
FileInputStram与FileOutputStream类都是用来操作磁盘文件,如果用户的文件读取/写入需求比较简单,则可以使用FileInputStream类和FileOutputStream类,参数构造函数相同。
FileInputStream(String name)(给定文件名)||FileInputStream(File file)(给定File对象);
使用FileOutputStream向文件中写入数据时,默认指定的文件不存在时,会先创建一个,在将输入内容写入文件,如果已存在,则先清空原来文件中的内容,在写入新文件,如果要在原文件末尾追加,需要使用FileOutputStream(String name ,boolean append)构造方法创建一个文件输出流。其中append的参数值为true。不能指定一个已经被其他程序打开的文件。
字节流中带缓存的输入/输出流
BufferedInputStream类可以对所有的InputStream类进行带缓存区的包装以达到性能的优化,BufferedOutputStream类与OutputStream不一样的是存在一个flush()方法用来将缓存区的数据强制输出完,就是在缓存区没有满的情况下,也将该缓存区的内容强制写入外设,习称刷新,只对OutputStream的子类有效,在调用close方法时,也会刷新。构造方法相同。
BufferedOutputStream(OutputStream in)(创建32字节的缓存区)||BufferedInputStream(OutputStream in,int size)(指定缓存区szie)
字节流中数据输入流和输出流
DataInputStream与DataOutputStream类允许应用程序以与机器无关的方式从底层输入流中读取基本的Java数据类型,即读取该数据时不关心字节。构造方法:
DataInputStream(InputStream in)(以基础的InputStream创建一个DataInputStream);只提供readUTF()方法返回字符串
DataOutputStream(OutputStream out)(创建一个新的数据输出流,将数据写入到指定基础输出流)写入方法有三种:writeBytes(String s),writeChars(String s),WriteUTF(String s)
ZIP压缩输入/输出流
ZIP压缩管理文件(ZIP archive)是一种十分典型的文件压缩形式,使用可以节省空间,java.util.zip包中的ZipOutputStream与ZipInputStream类来实现文件的压缩/解压缩。要从ZIP压缩管理文件内读取某个文件,要先找到对应该文件的“目录进入点(确定文件在ZIP文件的的位置点)”,如果要写入文件到zip文件内,必须先写入到对应文件的"目录进入点"。并且把要写入文件内容的位置移到此进入点所指的位置,然后写入文件。Java实现了I/O数据流与网络数据流的单一接口,ZipEntry类产生的对象,用来代表一个ZIP压缩文件的进入点(entry).ZipInputStream类用来读取ZIP压缩格式的文件,所支持的包括已压缩及未压缩的进入点(entry).ZipOutputStream类用来写出ZIP压缩格式的文件,支持包括已压缩和未压缩的进入点(entry)
压缩文件ZipOutputStream类对象,可以将文件压缩为.zip文件,构造方法:
ZipOutputStream(OutputStream out);
putNextEntry(ZipEntry e) | void | 开始写入一个新的ZipEntry,并将流内的位置移至此entry所指数据的开头 |
write(byte[] b, int off,int len) | void | 将字节数组写入到当前ZIP条目数据 |
finish() | void | 完成写入ZIP输出流的内容,无需关闭它所配合的OutputStream |
setComment(String comment) | void | 可设置此ZIP文件的注释文字 |
ZipInputSertam类可读取ZIP压缩格式的文件,包括已压缩和未压缩的条目(entry),ZipInputStream构造方法:
ZipInpusertam(InputStream in)
read(byte[] b,int off,int len) | int | 读取目录b数组内off偏移量的位置,长度是len字节 |
available() | int | 判断是否已读完目前entry 所指定的数据,读完返回0,反之1 |
closeEntry() | void | 关闭当前ZIP条目并定位流已读取下一个条目 |
skip(long n ) | long | 跳过当前ZIP条目中指定的字节数 |
getNetEntry() | ZipEntry | 读取下一个ZipEntry,并将流内的位置移至该entry所指定数据的开头, |
createZipEntry(String name) | ZipEntry | 以指定的name参数新建一个ZipEntry对象 |
字符流
Java语言中字符采用Unicode字符编码,每个字符占两个字节空间,文本有可能采用GBK和UTF-8,字符流的两个基本抽象类Reader和Writer,其他的字节流都是由这两个字节流派生的。
Reader(字符输入流):用于以字符为单位向数据源中读取数据。Reader类中常用方法
int read() | 读取一个字符并返回,如果遇到源的末尾,则返回-1 |
int read( char[] b) | 将数据读入到字符数组中,并返回实际读取的字符数,当已达到流的尾端而没有可以使用的字符时,返回-1 |
int read(cahr[] b,int offset,int len) | 将数据读入到字符数组中,并返回实际读取的字符数,当已达到流的尾端而没有可以使用的字符时,返回-1,len表示读取的最大字符数,offset表示数组中存放数据的开始位置。 |
void close() | 关闭此Reader流,并释放与该流关联的所有系统资源。 |
Reader | BufferedReader(缓存字符输入流,从字符输入流中读取文本,缓存各个字符,一次读取一行文本) | LineNumberReader |
CharArrayReader(字符数组读取器,此类实现一个可用作字符输入流的字符缓存区) | ||
InputStreamReader(将字节流转换成字符流,读出字节并且将其按照指定的编码方式转换成字符) | FileReader | |
FilterReader(字符文件输入流,用于读文件中的数据) | PushbackReader | |
PipedReader | ||
StringReader(字符串输入流,用于读文件中的数据) |
Writer(字符输出流):用于以字符为单位向数据源中写入数据。Write类中常用方法
void writer(int c) | 写入单个字符 |
void writer(char[] b) | 写入字符数组 |
void writer(char[] b,int offset,int len) | 写入字符数组的某一部分 |
void writer(String str) | 写入字符串 |
Writer | BufferedWriter(缓存字符输出流,往字符输出流中写文本,缓存各个字符) | LineNumberReader |
CharArrayWriter(字符数组输出流,往字符输出流中写文本,缓存各个字符) | ||
OutputStreamWriter(将字符流转换为字节流,将要写入流中的字符编码为字节) | FileWriter | |
FilterWriter(文件字符输出流,往文件中写内容) | PushbackReader | |
PipedWriter | ||
StringWriter(字符串输出流) | ||
printWriter |
字符流的文件输入/输出流FileReader和FileWriter
FileReader顺序的的读取文件,只要不关闭流,每次调用read()方法就顺序读取源中其余的内容,直到源的末尾或流被关闭。
BufferedReader的readLine()方法一次读取文件中的一行内容。当读取到末尾是返回null;
字符流的带缓存的输入/输出流BufferedReader和BufferedWriter
都具有内部缓存机制,并可以以行为单位进行输入/输出,
字符数据读取文件过程:字符数据>>BufferedWriter>>OutputStreamWriter>>>>OutpitStream>>文件
read() | 读取单个字符 |
readLine() | 读取一个文本行,并将其返回为字符串,若无数据可读,则返回null |
BufferedWriter类常用的方法 |
|
write(String s,int off,int len) | 写入字符串的某一部分 |
flush() | 刷新该流的缓存 |
newLine() | 写入一个行分隔符 |
在使用BufferedWriter类的Writer方法时,数据并没有立刻写入输入流,而是首先进入缓存区中,如果想立刻将缓存区中的数据写入输入流,一定要调用flush()方法。
过滤流和转换流
过滤流:用于对一个已有的流行行连接和封装处理,以便更加便利的方式对数据读写操作,过滤流分为过滤输入流和过滤输出流。
FilterInputStream | LineNumberInputStream(跟踪输入信号流,以废弃) |
DataInputStream(与DateOutputStream搭配使用,可以按照与平台无关的方式从流中读取基本类型数据) | |
BufferedInputStream(利用缓存区来提高读取效率) | |
PushbackInputStream(能够把读取的一个字节压回到缓存区中,通常用做编译器扫描) |
FilterOutputStream | DataOutputStream(与DateInputStream搭配使用,可以按照与平台无关的方式从流中读取基本类型数据) |
BufferedOutputStream(利用缓存区来提高读取效率) | |
PrintStream(用于产生格式化输出)利用写入数据 |
转换流:InputStreamReader(将字节输入流转换为字符输入流),OutputStreamWriter(将字符输出流转化为字节输出流)
对象流
在Java中,使用对象流可以实现对象的序列化和反序列化操作。
对象的序列化与反序列化:对象的序列化(Serialize)是指将对象数据写入到一个输出流中的过程,而对象的反序列化是指从一个输入流中读取一个对象,将对象序列化后会转换成与平台无关的二进制字节流,从而允许将二进制字节流持久的保存在磁盘上,或通过网络将二进制传输到另一个网络节点,其他程序从网络或磁盘上获取这种二进制字节流,并将其反序列化后恢复成原来的Java对象。对象序列化功能非常简单,强大,广泛应用于RMI,Socket,Jms,EJB等技术。
对象序列化有两个特点:对象序列化可以在分布式应用中进行使用,分布式应用需要跨平台,跨网络,因此要求所有传递的参数,返回值都必须实现序列化。对象序列化不仅可以保存一个对象的数据,而且通过循环可以保存每个对象的数据。
在Java中,只有对象为序列化的,才可以保存到磁盘或通过网络传输。一个类的对象是可序列化的,则该对象必须实现java.lang包下的Serializable接口(标识性接口,没有任何方法)或Esternalizable接口。在实现Serializable接口时无需实现任何方法,它只是用于表明该类的实例对象是可以序列化的,只有实现才可以利用序列化工具保存和复原。
ObjectOutputStream和ObjectInputStream
ObjectOutputStream 是OutputStream的子类,该类也实现了ObjectOutput接口,其中ObjectOutput接口支持对象序列化:
构造函数:ObjectOutputStream(OutputStream outStream)throws IOException
final void writeObject(Object obj) | 写入一个obj对象到调用的流中 |
void writeInt(int i) | 写入一个32位int值到调用的流中 |
void writeBytes(String str) | 以字节序列形式将字符串srt写入到调用的流中 |
void writeChar(int c) | 写入16位的char的值到调用的流中。 |
ObjectInputStream 是InputStream的子类,该类也实现了ObjectInput接口,其中ObjectInput接口支持对象序列化:
构造函数:ObjectInputStream(InputStream InStream)throws IOException
final Object readObgect() | 从流中读取对象 |
int readInt() | 从流中读取一个整型值 |
String readUTF() | 从流中读取UTF-8格式的字符串 |
cahr readCahr() | 读取一个16位的字符 |
NIO
JDLK1.4开始新增的NIO,在包java.nio包及子包下。NIO也是用于数据的输入输出,但NIO采用内存映射文件的方式处理,将文件或文件的一段区域映射到内存中,提高访问效率。
java中与NIO有关的包:
java.nio包(包含各种与Buffer(缓存)相关的类)
Java.nio,channels包(与Channel(通道)和Selector相关的类)
java.nio.charset包(主要包括与字符集相关的类)
java.nio.channels.spi包(与Channel相关的服务提供者编程接口)
java.nio.charset.spi包(包括字符集相关的服务提供者编程接口)
Buffer和Channel是NIO的两个核心对象:
Buffer可以理解为一个容器,本质为一个数组,往Channel中发送或读取的对象都必须先放到Buffer中;在NIO系统中所有数据都需要经过通道传输,Channel与传统的InputStream,OutputSteam最大的区别是提供map()方法,可以将数据映射到内存中。IO是面向流的,NIO是面向块处理的,除了Buffer和Channel外,NIO还提供用于将Unicode字符串映射成字节序列。
Buffer类
Buffer是一个抽象类,其最常使用的子类是ByteBuffer,用于在底层字节数组上进行get/set()操作,除了布尔型,都有对应的Buffer类;CharBuffer……。没有构造方法,通过 static XxxxBuffer allocate(int capacity):创建一个指定容量的XxxBuffer对象。
MappedByteBuffer为Buffer的子类,表示Channel将磁盘文件的部分或全部内容映射到内存中所的到的结果,对象由Channel的map()方法返回。
使用Buffer涉及的三个概念;
容量(capacity):最大数据容量,创建后不能改变。界限(limit):之后的数据不能被读写,位置(position):用于指明下一个可以被读出或者写入的缓存区位置索引 ,标记(mark):允许position定位到mark处,关系:0<=mark<=position<=limit<=capacity.
int capacity() | 返回此缓存区的容量 |
Buffer clear() | 清除此缓存区 |
Buffer filp() | 反转此缓存区(limit与position互换) |
boolean hasRemaining() | 告知在当前位置和限制之间是否有元素 |
int limit() | 返回此缓存区的限制 |
Buffer limit(int newLimit) | 设置此缓存区的限制 |
Buffer mark() | 在此缓存区的位置设置标记 |
int posmaining() | 返回此缓存区的位置 |
Buffer position(int newPosition) | 设置此缓存区的位置 |
int remaining() | 返回当前位置与限制之间的元素数 |
Buffer reset() | 将此缓存区的位置重置为以前标记的位置 |
Buffer rewind() | 重绕此缓存区 |
Channel类
Channel与传统IO流相似,不同的地方Channel类可以直接将指定文件的部分或全部直接映射成Buffer;程序不能直接访问,Channel中的数据,Channel只能与Buffer进行交互。Channel是接口,其实现类包括DatagramChannel,FileChannel等,所有的Channel对象都不是通过构造器直接创建,而是通过传统结点InputStream或OutputStream的getChannel()f获取对应的Channel对象。不同流获取的对象不同。
MappedByteBuffer map(FileChannel. MapMode mode,long position,long size) | 将此通道的文件区域直接映射到内存中 |
int read(ByteBuffer dst) | 将字节序列从此通道读入给定的缓存区 |
int write(ByteBuffer src) | 将字节序列从给定的缓存区写入此通道 |
NIO.2
Java1.7对NIO改进称为NIO.2,改进方向:提供了全面的文件IO和文件系统的访问支持,新增java.nio.file包及其子包。新增了基于异步的Channel的IO,在Java.nio.channel包下增加了多个以Asynchronous开头的Channel接口和类。引入Path接口,该接口代表一个与平台无关的文件路径,提供Files和Paths两个工具类,Paths工具类提供了get()静态方法来创建Path实例对象。
public static Path get(String first,String...more) | 将路径字符串,或多个字符串连接形成一个路径的字符串序列,转换成一个Path对象 |
public static Path get(URL url) | 将给定的URL转换为一个Path对象 |
JDBC编程
使用JDBC,java程序可以轻松地操作各种主流数据库,Oracle,MSSQL,Mysq等,使用JDBC编写的程序不仅可以实现跨数据库,还具有跨平台性和可移植性。
JDBC(Java Database Connectiovity,Java数据库连接)是一种执行SQL语句的JavaAPI,程序可以通过JDBC API连接数据库,并使用SQL结构化查询语言完成对数据库的操作,程序员使用JDBC编程时只需要掌握标准的JDBC API 即可,当需要在不同的数据库之间切换时,只需要更换不同的数据库驱动类,是面向接口编程的典例应用。
JDBC访问数据库时主要完成三个操作:
- 建立与数据库的连接
- 执行SQL语句
- 获取执行结果
JDBC驱动: 数据库驱动程序是JDBC程序和数据库之间的转换层,数据库驱动程序负责将JDBC调用映射成特定的数据库调用,有4种类型:JDBC-ODBC桥(最早),本地API驱动,网络协议驱动,本地协议驱动(建议使用,纯java编写)。
JDBC API:提供一组用于与数据库进行通信的接口和类,都定义在java.sql包下。
DriverManager | 用于管理JDBC驱动的服务类,该类的主要功能是加载和卸载各种驱动程序,建立数据库连接并获取连接对象 |
Connection | 该接口代表数据库的连接,要访问数据库必须先获得数据库的连接 |
Statement | 用于执行SQL语句的工具接口,当执行查询语句时返回一个查询到的结果集 |
PreparedStatement | 该接口用于执行预编译的SQL语句,这些SQL语句带有参数,避免数据库每次都需要编译SQL语句,执行时传参即可 |
CallableStatement | 该接口用于调用SQl储存过程 |
ResultSet | 该接口表示结果集,包含访问查询的各种方法 |
使用JDBC API中的类或者接口访问数据库时,容易引发SQLException异常,属于检查性异常。需要放在try……catch语句里,对于DriverManager来讲,要用到ClassNotFoundException异常。
DriverManager类:是数据库驱动管理类,用于管理一组JDBC驱动程序的基本服务,应用程序和数据库之间可以通过DriverManager建立连接,
static connection getConnection(String url,String user,String password) | 获取指定的URL的数据库连接,其中url为提供了一种标识数据库位置的方法,user用户名,password密码 |
static Driver getDriver(String url) | 返回能够打开url所指定的数据库的驱动程序 |
Connection接口:用于连接数据,每个Connection代表一个数据库连接会话,一个应用程序可以与单个或者多个数据库连接,通过DriverManager类的getConnection()方法可以返回同一个Connection对象,该对象提供创建SQL的语法,完成基本SQL操作
void close() | 断开连接,释放此Connection对象的数据库和JDBC资源 |
Statement createStatement() | 创建一个Statement对象来将SQL语句发送到数据库 |
void commit() | 用于提交SQL语句,确认从上一次提交/回滚以来进行的所有更改 |
boolean isClosed() | 用于判断Connection对象是否已经被关闭 |
CallableStatement prepareCall(String sql) | 创建一个CallableStatement对象来调用数据库储存过程 |
PrepareStatement(String sql) | 创建一个PreparedStatement对象来将参数化的SQL语句发送到数据库 |
void rollback() | 用于取消SQL语句,取消在当前事务中进行的所有更改 |
Statement接口:一般用于执行SQL语句,在JDBC中要执行SQL查询语句的方式有一般查询(Statement),参数查询(PrepareStatement)和储存查询(CallableStatement )三种方式。Statement和PreparedStatement和CallableStatement三个接口具有依次继承关系。Statement接口的主要功能是将SQL语句传送给数据库,并返回SQL语句的执行结果,Statement提交的SQL语句是静态的,不需要接受任何参数,SQL语句可以包含三种类型语句:SELECT查询语句,DML语句,DDL语句。
void close() | 关闭Statement对象 |
boolean execute(String sql) | 执行给定的SQL语句,可以返回多个结果 |
ResultSet executeQuery(String sql) | 执行给定SQL语句,返回单个ResultSet对象 |
int executeUpdate(String sql) | 执行给定的SQl语句,可以为DML语句或者DDL语句,返回影响行数 |
Connection getConnection() | 获取生成此Statement对象的Connection对象 |
int getFetchSize() | 获取结果集合的行数,该数是根据此Statement对象生成的ResultSet对象的默认获取大小 |
int getMaxRows() | 获取由此Statement对象生成的ResultSet对象可以包含的最大行数 |
ResultSet getResultSet() | 获取由此Statement执行查询语句返回的的ResultSet对象 |
int getUpdateCount() | 获取此Statement执行DML语句所影响的记录个数 |
void cioseOnComplection() | 当所有依赖Statement对象的ResultSet结果集关闭时,该Statement会自动关闭 |
boolean isCloseOnCompletion() | 判断是否打开closeOnCompletion() |
long executeLargeUpdate(String sql) | 增强版读完executeUpdate()方法,记录数超过Integer时使用,为long |
ResultSet接口:用于封装结果集对象,该对象包含访问查询结果的方法,使用Statement中的executeQuery()方法可以返回一个ResultSet结果集对象(f封装了所有查询条件的记录),ResultSet具有指向当前数据行的游标,并提供了许多方法来操作结果集中的游标,提供getXXX()方法对结果集进行访问。调用next()方法游标会向下移动,
boolean absolute(int row) | 将游标移动到row条记录 |
boolean relative(int rows) | 按相对行数(正或负)移动游标 |
void beforeFirst() | 将游标移动到结果集的开头(第一行前) |
boolean first() | 将游标移动到结果集的第一行 |
boolean previous() | 将游标移动到结果集的上一行 |
boolean next() | 将游标移动到结果集中当前位置的下一行 |
boolean last() | 将游标移动到结果集的最后一行 |
void afterlast() | 将游标移动到结果集的末尾(最后一行后) |
boolean isAfterLast() | 判断游标是否位于结果集的末尾(最后一行后) |
boolean isBeforeFirst() | 判断游标是否位于结果集的开头(第一行前) |
boolean isFirst() | 判断游标是否位于结果集的第一行 |
boolean isLast() | 判断游标是否位于结果集的最后一行 |
int getRow() | 检索当前行编号 |
String getString(int x) | 返回当前行第X列的列值,类型为String |
int getInt(int x) | 返回当前行第X列的列值,类型为int |
Statement getStatement() | 获取生成结果集的Statement对象 |
void close() | 释放此ResultSet对象的数据库和JDBC资源 |
ResultSetMetaData getMetaData() | 获取结果集的列的编号,类型,和属性 |
数据库环境搭建:1,创建数据库表。2设置Oracle驱动类路径(Oracledatabase所提供的JDBC驱动程序(jre文件)导入到工程中)。
数据库访问:使用JDBC访问数据库步骤:
- 加载数据库驱动:Class.forName("数据库驱动类名");mysql:com.mysql.jdbc.Driver;oracle:oracle.jdbc.driver.OracleDriver;
- 建立数据连接:Connection conn = DriverManager.getConnection(String url,String user,String pass); mysql:DriverManager.getConnection("jdbc:mysql://localhost:3306/shop", "root","mysql"); oracle:DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","sys as sysdba","oracle");
- 创建Statement对象:通过Connection对象获取Statement的方法; createStatement()//创建一个基本的Statement对象。prepareStatement(String sql)//根据参数化的SQL语句创建一个预编译的PreparedStatement对象。PrepareCall(String sql)//根据SQL语句创建一个CallableStatement对象,用于调用储存过程。
- 执行SQl语句:获取Statement对象后,可以调用该对象的不同方法来执行SQL语句,有三种执行SQl语句的方法。 executeQuery():只能执行查询语句,用于产生单个结果集。executeUpdate()和executeLargeUpdate():用于执行DML和DDL语句,返回对应的行数和0;execute():可以执行任何SQL语句返回值为布尔型。Statement对象将结果集分装为ResultSet对象并返回
- 访问结果集:SQL的查询结果使用ResultSet封装,ResultSet结果集中包含了满足SQL查询条件的所有的行,使用getXXX()方法对结果集进行数据访问,通过列索引和列名获取游标所指的列数据,通过next()和循环控制游标。
- 关闭对象:关闭结果集,Statement对象,连接对象。
操作数据库:
Statement接口:
execute()方法可以执行任何SQL语句,返回值为布尔型表示是否返回了ResultSet对象,true时使用Statement的getResultSet()方法来获取execute()方法执行SQL语句返回的ResultSet对象;false时使用getUpdateCount()方法获取受影响得行数。executeUpdate()和executeLargeUpdate():用于执行DML和DDL语句,返回对应的行数和0;当DML语句影响的记录超过Integer.MAX_VALUE时,使用executeLargeUpdate(),类型为long;
PreparedStatement接口:
PreparedStatement对象包含的SQL语句进行预编译,需要多次执行相同的SQL语句时,编译好的语句比Statement对象快。可以执行动态的SQL语句,即在SQL 语句中提供参数,动态SQL语句中用?作为动态参数的占位符。用setXXX()的方法通过占位符的索引完成对参数的赋值。
例:String insterSql = "INSERT INTO LIRUILONG.my_tests VALUES(?,?)";
PreparedStatement ps = conn.prepareStatement(insterSql);
ps.setInt(1,4);
ps.setString(2, "李瑞龙");
CallableStatement接口:
JDBC提供CallableStatement接口,用于执行数据库的储存过程,该接口可以处理一般的SQL 语句,也可以处理以三种带参数(IN ,OUT,IN OUT)的SQL储存过程,使用Connection类的prepareCall(String sql)方法可以创建一个CallableStatement对象,方法的参数可以是一个调用存储过程的字符串,cast = conn.prepareCall("{call LIRUILONG.addSub(?,?)");对CallableStatement的SQL语句执行一般用execute().
调用存储过程的SQL:“{call 存储过程名[(参数占位符?)]}”、、有返回值的:“{参数占位符?=call 存储过程名[(参数占位符?)]}”
CallableStatement接口通过setXXX()方法对IN参数进行赋值,
通过registerOutParameter(1, sql.Types.)方法对OUT参数进行类型注册,第二个参数通常使用java.sql.Types静态常量指定。
检索结果的获取通过getXXX()方法获取OUT和IN OUT参数的值,
对于IN OUT 参数的值来讲需要先使用setXXX()方法对参数进行设置,然后使用registerOutParameter()进行类型注册,最后使用getXXX()方法来获取检索结果
数据库访问优化:
即编写一个数据库访问工具类DBUtil,用于提供访问数据库时所用到的连接,查询等
- 编写属性文件:存放连接数据库的参数信息,在项目的更目录下创建一个config子目录。并添加一个属性文件oracle.properties,该文件以键-值对的形式保存连接Oracle的配置信息。在读取配置文件的配置信息时,需要编写一个Config配置类,在给类中通过java.util.Properrties类的get()方法来获取指定的“键”所对应的值。
- 编写DBUtil工具类。将SQL语句与参数包装传递
- 使用DBUtil工具类。
集元数据
集元数据(Meta Data)是有关数据库和表结构的信息,JDBC提供了获取这些信息的DatabaseMetaData和ResultSetMetaData接口。
DatabaseMetaData接口:DatabaseMetaData接口主要用于获取数据库相关信息,如数据库的所有表的列表,系统函数,关键字,数据库产品名以及驱动类型。DatabaseMetaData对象通过getMetaData()方法进行获取。DatabaseMetaData接口提供大量获取信息的方法,这些方法可分为两大类:
- 返回值为boolean型,多用于检查数据库或驱动器是否支持某项功能,
- 获取数据库或驱动的参数特征值。
boolean supportsOuterJolns() | 检查数据库是否支持外部连接 |
boolean supportsStoredProcedures() | 检查数据库是否支持储存过程 |
String getURL() | 返回用于连接数据库的URL地址 |
String getUserName() | 获取当前的用户名 |
String getDatabaseProductName() | 获取使用的数据库产品名 |
String getDatabaseProductVersion() | 获取使用的数据库版本号 |
String getDriverName() | 获取用于连接的驱动类型名称 |
String getProductVerslon() | 获取用于连接的驱动器版本号 |
ResultSet getTypeInfo() | 获取数据库中可能取得的所有数据类型的描述 |
ResultSetMetaData接口
用于获取结果集的结构信息,通过ResultSet的getMetaData()方法来获取对应的ResultSetMetaData对象
int getColumnCount() | 返回此ResultSst对象中的列数 |
String getColumnName(int column) | 获取指定列的名称 |
int getColumnType(int cloumn) | 检索指定列的SQL类型 |
String getTableName(int column) | 获取指定列的表名 |
int getColumnDisplaySize(int column) | 指示指定列的最大标准宽度,以字符为单位 |
boolean isAutoIncrement(int column) | 指示是否为自动为指定列中进行编号,这些列任然为只读 |
int isNullable(int column) | 指示指定列中的值是否可以为null |
boolean isSearchable(int column) | 指示是否可以在where子句中使用指定的列 |
boolean isReadOnly(int column) | 指示指定法人列是否明确不可写入 |
事务处理:
事务是保证底层数据完整的重要手段由一步或几步数据库操作序列注组成的逻辑执行单元。事务具有ACID四个特性:
原子性(Atomicity):事务是应用中的最小执行单位,具有不可在分的特性,全部完成或不执行。
一致性(Consistency):事务执行前后数据库都必须是出于一致状态。
隔离性(Isolation):各个事务互不干扰,及并发事务间互不影响。
持久性(Durability):事务一旦提交,对数据库的的物理存储进行改变,不被丢失。
事务处理包括事务提交,终止和回滚,事务提交分显式提交(commit)和自动提交,事务终止指未能成功完成事务,执行中断,事务回滚有显式回滚(rollback)和自动回滚(系统错误或强行退出)
JDBC对事务操作由Connection提供:开启事务,执行任意多条DML语句,执行成功提交事务,失败回滚事务,Connection在默认情况下会自动提交,及事务是关闭的,一条SQL语句执行后,系统调用commit()方法提交数据库,无法回滚,使用Connection的setAutoCommit()方法可以开启关闭自动提交模式(事务),该方法为布尔型,参数false为关闭自动提交,反之打开自动提交。
开启事务:conn.setAutoCommit(false);提交事务:conn.commit();回滚事务:conn.rollback();
当程序遇到未处理的SQLException异常,都会自动回滚,当捕获该异常时,则需要在处理块中显示回滚。
保存点操作:使用Savepoint类声明一个保存点对象(Savepoint s1),在需要的位置设置保存点(s1= conn.setSavepoint();)在回滚操作中可以回滚到保存点位置(conn.rollback(s1));
批量更新:即多条SQL语句被作为一批操作同时收集,并同时提交,必须得到底层数据库的支持,调用DatabaseLargeBatch()方法查看底层数据库是否支持批量更新。创建一个Statement对象,使用Statement对象的addBatch()方法收集多条SQL语句,调用Statement的executeBatch()或者executeLargeBatch()方法同时提交所有的SQL语句。
Swing UI设计
GUI概述:图形用户界面(Graphical User Interface ,GUI)的形式。Java提供AWT(Abstract Windows Tookit ,抽象窗口工具集)和Swing来实现GUI图形用户界面编程。
AWT,Swing。2D,API,辅助功能API以及拖放API共同组成JFC(Java Foundation Class ,Java基础类库)。
使用Swing组件进行GUI编程的优势有以下几点:
- Swing用户界面组件丰富,使用优雅。
- Swing组件对底层平台的依赖少,与平台的BUG也少。
- 能够保证不同平台用户一致的感官效果。
Swing组件层次
大部分Swing组件都是JComponent抽象的直接或间接子类,在JComponent 抽象类中定义了所有子类组件的通用方法, JComponent类位于javax.swing的java扩展包中。
JComponent类的继承层次(由父类到子类以下都是):java.lang.Object,java.awt.Comtainer,java.awt.Container,java.swing.Component.
将Swing组件按功能划分:
顶层容器:JFrame,JApplet,JDialog,JWindow。
中间容器:JPanel,JScrollPane,JSplitPane和JToolBar等
特殊容器:特殊作用的中间容器,如JInternalFrame,JRootPane和JLayeredPane等。
基本组件:与用户交互的组件,如JButton,JComboBox,JList,JMenu和JSlider等。
特殊对话框:直接产生特殊对话框组件,如JColorChooser和JFileChooser等。
不可编辑信息的显示组件:组件中的信息不可编辑,如JLable,JProgressBar和JToolTip等;
可编辑信息的显示组件:组件中的信息可以编辑,如JTeXField,JTextArea和JTable等。
容器:可以用来存放其他组件,而容器的本身也是一个组件,属于Component的子类。容器具有组件的所有性质,同时还具备容纳其他组件的容器功能。
JFrame顶级容器:
Jframe(窗口框架):是可以独立存在的顶级窗口容器,能够包含其他子容器,但不能被其他容器所包含。JFrame继承了java,awt.Frame.类;java.lang.Object,java.awt.Component,java.awt.Window,java.awt.Frame,javax.swing.JFrame. 构造方法如下want to sy:
JFrame():不带参数的构造方法,该方法用于创建一个初始不可见的新窗体。
JFrame(String title):带一个字符串的参数,创建一个初始不可见的新窗体,窗口标题为字符串参数。
protected void frameInit() | 在构造方法中调用该方法用来初始化窗体 |
public Compoent add(Component comp) | Container 的子类,用于向窗口添加组件 |
public voidsetLocation(int x,int y ) | Component的子类,用于设置窗口位置坐标 |
public void setSize(int width ,int height) | 从Window中继承而来,用于设置窗口大小 |
public void setVisble(boolean b) | 从window中继承而来,用于设置是否可视,当参数为true时可视,反之隐藏 |
public void setContentPane(Container contentPane) | 设置容器面板 |
public void setIcomImage(Image) | 设置窗体左上角的图标 |
public void setJMenuBar(JMenuBar menubar) | 设置窗体的菜单栏 |
public void setDefaultCloseOperation(int operation) | 设置用户对此窗体的默认关闭操作,参数为常量: DO_NOTHING_ON_CLOSE:不执行任何操作 HIDE_ON_CLOSE:自动隐藏该窗体 DISPOSE_ON_CLOSE:自动隐藏并释放该窗体 EXIT_ON_CLOSE:退出应用程序 |
public void setTitle(String title) | 从Frame类中继承而来,用于设置窗口标题 |
JPanel(面板)中间容器
JPanel类与顶级容器不同,不能独立存在,必须放在其他容器中,JPanel中间容器的意义在于为其他组件提供空间,使用时,一般先将其他组件添加到JPanel中间容器中,然后在将JPanel中间容器添加到JFrane顶级容器中。
java.lang.Object,java.awt.Component,java.awt.Container,java.swing.JCompoent,javax.swing.JPanel;构造方法如下:
JPanel():不带参数的构造方法,用于创建一个默认为流布局(FlowLayout)的面板
JPanel(LayoutManager layout):参数为一个布局管理器,创建一个指定布局的面板。
public Component add(Compoent comp) | 从Container类中继承而来,用于向面板容器中添加其他组件 |
public void setLayout(LayoutManager mgr) | 从Container类中继承而来,设置面板的布局方式 |
布局
布局管理器用来管理组件在容器中的布局格式,当容器中容纳多个组件时,使用布局管理器对组件进行排列和分布。AWT提供FlowLayout(流布局),BorderLayout(边界布局),GridLaout(网格布局),GridBagLayout和CardLayout(卡片布局)五个常用布局管理器,Swing提供BoxLayout(盒布局)布局管理器还有NULL布局。
FlowLayout流布局:组件从左到右,从上到下,流动的排布分列,构造方法:
FlowLayout():使用默认对其方式(中间对其)和默认间距的方式(水平垂直5px)创建新的流布局管理器。
FlowLayout(int align):带有对齐方式参数的构造方法,
FlowLayout(int align,int hgap,int vgap):带有对齐方式,水平垂直间距的流布局管理器。
FlowLayout.LEFT:左对齐,FlowLayout.CENTER:居中对齐,默认方式,FlowLayout.RIGHT:右对齐。
FlowLayout是面板的默认布局,创建一个面板时默认流布局。当容器采用FlowLayout流布局时,改变窗体大小,各组件的位置会随窗体变化而变化,大小不变保持原来大小。
BorderLayout边界布局:允许组件有选择的放置在容器的中东南西北五个区域。在向容器中添加组件时,要指定位置
add(Componentcomp,int index),一般只能放置一个组件,多个时,后放置的组件会被覆盖,构造函数:
BorderLayout():创建一个无间距的边界布局管理器。
BorderLayout(int hgap, int vgap):创建一个指定水平垂直边距的边界布局管理器。
BorderLayout.EAST/WEST/SOUTH/NORTH/CENTER=东西南北中(默认)。
BorderLayout边界布局是窗体(JFrame)的默认布局,使用边界布局,改变窗体,组件拉伸扩展
GridLayout网格布局:像表格一样,等大分割窗体,添加组件默认左到右,上到下,组件随窗体变化。构造方法:
GridLayout(int rows,int cols):创建指定行数和列数的布局管理器。
GridLayout(int rows,int cols,int hgap,int vgap):用于创建一个指定行数,列数水平间距和垂直间距的的网格布局管理器。
CardLayout卡片布局:将组件看做是重叠的卡片加入容器中,每次只能看到对上面的,以时间来管理容器的组件。构造方法:
CardLayout()创建默认间距为0的布局管理器对象。
CardLayout(int hgap,int vgap):带参数的构造方法,指定水平垂直间距的卡片布局管理器对象。
first(Container parent) | 显示容器中第一张卡片 |
last(Container parent) | 显示容器最后一张卡片 |
previous(Container parent) | 显示当前卡片的上一张 |
next(Container parent) | 显示当前卡片的下一张 |
show(Container parent) | 显示指定名称的卡片 |
一个容器使用CardLayout卡片布局后,向容器中添加组件时,使用两个参数的add()方法。add(String name ,Container comp);给组件指定名字。卡片组件的大小随窗体变换变换。
BoxLayout盒布局:Swing引入新的布局管理器,可以在水平垂直两个方向摆放布局。构造:BoxLayout(Container target,int axis);创建一个基于target容器,沿给定轴放置的组件的盒布局管理器对象。
BoxLayout.X_AXIS/Y_AXIS=X轴/Y轴排列。LINE_AXIS:根据容器的ComponentOrienation属性,按照文字在一行的排列布置组件。
PAGE_AXIS:根据容器的ComponentOrienation属性,按照文本行在一页的排列布置组件。
NULL空布局:可以采用混合布局(多个布局管理器结合使用)或者采用NULL布局,即不采用任何布局,通过组件的绝对定位进行布局。
使用NULL布局的步骤:
- 设置面板对象布局为空,p.setLayout(null);
- 调用setBounds()设置组件绝对位置的坐标和大小。或使用setLocation(),和setSize()设置组件的最
- 将组件添加到容器中。
NULL用于组件位置相对固定的,窗口不允许随便变换大小,否则会偏移。