使用GZIP和Zip压缩Java数据流

转载自   使用GZIP和Zip压缩Java数据流

本文通过对数据压缩算法的简要介绍,然后以详细的示例演示了利用java.util.zip包实现数据的压缩与解压,并扩展到在网络传输方面如何应用java.util.zip包现数据压缩与解压

综述

许多信息资料都或多或少的包含一些多余的数据。通常会导致在客户端与服务器之间,应用程序与计算机之间极大的数据传输量。最常见的解决数据存储和信 息传送的方法是安装额外的存储设备和扩展现有的通讯能力。这样做是可以的,但无疑会增加组织的运作成本。一种有效的解决数据存储与信息传输的方法是通过更 有效率的代码来存储数据。这篇文章简要的介绍了数据的压缩与解压缩,并展示了用java.util.zip包来实现数据的压缩与解压缩是多么的方便与高 效。

当然用诸如WinZip,gzip,和Java压缩(或jar)之类的工具也可以实现数据的压缩与解压缩,这些工具都是独立的应用程序。你也可以在 JAVA应用程序中调用这些工具,但这并不是最直接的方法,也不是有效的解决方法。尤其是你想更快速地实现数据的压缩与解压缩(例如在传输数据到远程机器 之前)。这篇文章包括以下内容:

  • 给出一个关于数据压缩的简单的介绍
  • 描述java.util.zip包
  • 示例如何使用该包实现数据的压缩与解压缩
  • 示例如何压缩串行化的对象并将其存储在磁碟上
  • 示例如何通过数据压缩来增强"客户/服务"应用程序的性能

数据压缩概述

文件中数据冗余的最简单的类型是"字符的复制"。让我们先来看下面一个字符串:

  • JJJJJJAAAAVVVVAAAAAA 这个字符串可以用更简洁的方式来编码,那就是通过替换每一个重复的字符串为单个的实例字符加上记录重复次数的数字来表示,上面的字符串可以被编码为下面的形式:

  • 6J4A4V6A 在这里,"6J"意味着6个字符J,"4A"意味着4个字符A,以此类推。这种字符串压缩方式称为"行程长度编码"方式,简称RLE。

再举一个例子,考虑一下矩形图像的存储。一个单色位图,可以被存储为下面这种形式,如图1所示。


另外一种方式是将图像存为一个图元文件:

Rectangle 11, 3, 20, 5

上面的表示方法是讲矩形的起始坐标是(11,3),宽度是20,高度是5。

上述的矩形图像可以使用RLE编码方式压缩,通过对相同位记数表示如下:

0, 40
0, 40
0,10 1,20 0,10
0,10 1,1 0,18 1,1 0,10
0,10 1,1 0,18 1,1 0,10
0,10 1,1 0,18 1,1 0,10
0,10 1,20 0,10
0,40

上面第一行是讲图像的第一行由40个0组成。第三行是讲图像的第三行是由10个0加上20个1再加上10个0组成,其它行以此类推。

大家注意,RLE方法需要将其表示的文件与编码文件分开。所以,这种方法不能应用于所有的文件。其它的压缩技术包括变长编码(也被称为哈夫曼编码),还有其它的方法。要想了解更详细的信息,请参考有关数据和图像压缩技术方面的图书,一定会有收获的。

数据压缩有很多益处。不管怎么说,最主要的好处就是减少存储方面的需求。同样的,对于数据通信来讲,压缩数据在媒体中的将导致信息传输数据的提升。 数据的压缩能够通过软件在现有的硬件设备上实现或者通过带有压缩技术的特殊的硬件设备来实现。图表2显示了基本的数据压缩结构图。


ZIP VS GZIP

如果你是在Windows系统下工作,你可能会对工具WinZip很熟悉,是用来创建压缩档案和解开压缩档案的。而在UNIX平台上,会有一些不同,命令tar用来创建一个档案文件(并不压缩),其它的程序(gzip或compress)用来创建一个压缩档案。

WinZip和PkZip之类的工具同时扮演着归档和压缩两个角色。他们将文件压缩并将其归档。另一方面,gzip并不将文件归档。所以,在UNIX平台上,命令tar通常用来创建一个档案文件,然后命令gzip来将档案文件压缩。

Java.util.zip包

Java提供了java.util.zip包用来兼容ZIP格式的数据压缩。它提供了一系列的类用来读取,创建,修改ZIP和GZIP格式的文件。 它还提供了工具类来计算任意输入流的数目,这可以用来验证输入数据的有效性。该包提供了一个接口,十四个类,和两个异常处理类,如表1所示。

条目类型描述
Checksum接口被类Adler32和CRC32实现的接口
Adler32使用Alder32算法来计算Checksum数目
CheckedInputStream一个输入流,保存着被读取数据的Checksum
CheckedOutputStream一个输出流,保存着被读取数据的Checksum
CRC32使用CRC32算法来计算Checksum数目
Deflater使用ZLIB压缩类,支持通常的压缩方式
DeflaterOutputStream一个输出过滤流,用来压缩Deflater格式数据
GZIPInputStream一个输入过滤流,读取GZIP格式压缩数据
GZIPOutputStream一个输出过滤流,读取GZIP格式压缩数据
Inflater使用ZLIB压缩类,支持通常的解压方式
InlfaterInputStream一个输入过滤流,用来解压Inlfater格式的压缩数据
ZipEntry存储ZIP条目
ZipFile从ZIP文件中读取ZIP条目
ZipInputStream一个输入过滤流,用来读取ZIP格式文件中的文件
ZipOutputStream一个输出过滤流,用来向ZIP格式文件口写入文件
DataFormatException异常类抛出一个数据格式错误
ZipException异常类抛出一个ZIP文件

注意:ZLIB压缩类最初是作为可移植的网络图像文件格式(PNG)标准的一部分开发的,是不受专利保护的。

从ZIP文件中解压缩和提取数据

java.util.zip包提供了数据压缩与解压缩所需要的类。ZIP文件的解压缩实质上就是从输入流中读取数据。Java.util.zip包 提供了类ZipInputStream来读取ZIP文件。ZipInputStream流的创建与其它输入流的创建没什么两样。举个例子,下面的代码段创 建了一个输入流来读取ZIP格式的文件:

FileInputStream fis = new FileInputStream("figs.zip");
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis));


ZIP输入流打开后,你可以使用getNextEntry方法来读取ZIP文件中的条目数,该方法返回一个ZipEntry对象。如果到达文件的尾部,getNextEntry返回null:

ZipEntry entry;
while((entry = zin.getNextEntry()) != null) {// extract data// open output streams
}

现在,你应该建立一个输出流,如下所示:

int BUFFER = 2048;
FileOutputStream fos = new FileOutputStream(entry.getName());
BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);

注意:在这段代码中我们用BufferedOutputStream代替了ZIPOutputStream。 ZIPOutputStream和GZIPOutputStream使用内置的512字节缓冲。当缓冲区的大小大于512字节时,使用 BufferedOutputStream才是正确的(例子中设置为2048)。ZIPOutputStream不允许你设置缓冲区的大 小,GZIPOutputStream也是一样,但创建 GZIPOutputStream 对象时可以通过构造函数的参数指定内置的缓冲尺寸。

这段代码中,使用ZIP内含的条目名称创建一个文件输出流。可以使用entry.getName来得到它的返回句柄。接着读出被压缩的源数据,然后写入输出流:

while ((count = zin.read(data, 0, BUFFER)) != -1) {//System.out.write(x);dest.write(data, 0, count);
}

最后,不要忘记关闭输入和输出流:

dest.flush();
dest.close();
zin.close();

例程1的源程序UnZip.java显示如何解压缩并从ZIP档案中将文件释放出来。测试这个例子,编译这个类,并运行它,传给它一个ZIP格式的文件作为参数:

prompt> java UnZip somefile.zip

注意:somefile.zip应该是一个ZIP压缩档案,可以用任何一种ZIP压缩工具来创建,例如WinZip。

UnZip.java
import java.io.*;
import java.util.zip.*;
public class UnZip {static final int BUFFER = 2048;public static void main (String argv[]) {try {BufferedOutputStream dest = null;FileInputStream fis = new FileInputStream(argv[0]);ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));ZipEntry entry;while((entry = zis.getNextEntry()) != null) {System.out.println("Extracting: " +entry);int count;byte data[] = new byte[BUFFER];// write the files to the diskFileOutputStream fos = new FileOutputStream(entry.getName());dest = new BufferedOutputStream(fos, BUFFER);while ((count = zis.read(data, 0, BUFFER)) != -1) {dest.write(data, 0, count);}dest.flush();dest.close();}zis.close();} catch(Exception e) {e.printStackTrace();}}
}

有一点值得大家注意,类ZipInputStream读出ZIP文件序列(简单地说就是读出这个ZIP文件压缩了多少文件),而类ZipFile使用内嵌的随机文件访问机制读出其中的文件内容,所以不必顺序的读出ZIP压缩文件序列。

注意:ZIPInputStream和ZipFile之间另外一个基本的不同点在于高速缓冲的使用方面。当文件 使用ZipInputStream和FileInputStream流读出的时候,ZIP条目不使用高速缓冲。然而,如果使用ZipFile(文件名)来 打开文件,它将使用内嵌的高速缓冲,所以如果ZipFile(文件名)被重复调用的话,文件只被打开一次。缓冲值在第二次打开进使用。如果你工作在 UNIX系统下,这是什么作用都没有的,因为使用ZipFile打开的所有ZIP文件都在内存中存在映射,所以使用ZipFile的性能优于 ZipInputStream。然而,如果同一ZIP文件的内容在程序执行期间经常改变,或是重载的话,使用ZipInputStream就成为你的首选 了。

下面显示了使用类ZipFile来解压一个ZIP文件的过程:

  1. 通过指定一个被读取的ZIP文件,或者是文件名,或者是一个文件对象来创建一个ZipFile对象: ZipFile zipfile = new ZipFile("figs.zip");

  2. 使 用entries方法,返回一个枚举对象,循环获得文件的ZIP条目对象: while(e.hasMoreElements()) { entry = (ZipEntry) e.nextElement(); // read contents and save them }

  3. ZIP 条目作为参数传递给getInputStream方法,可以读取ZIP文件中指定条目的内容,能过其返回的输入流(InputStram)对象可以方便的 读出ZIP条目的内容: is = new BufferedInputStream(zipfile.getInputStream(entry));

  4. 获 取ZIP条目的文件名,创建输出流,并保存: byte data[] = new byte[BUFFER]; FileOutputStream fos = new FileOutputStream(entry.getName()); dest = new BufferedOutputStream(fos, BUFFER); while ((count = is.read(data, 0, BUFFER)) != -1) { dest.write(data, 0, count); }

  5. 最后关闭所有的输入输出流 dest.flush(); dest.close(); is.close();

完整的程序代码如例程2所示。再次编译这个文件,并传递一个ZIP格式的文件做为参数:

prompt> java UnZip2 somefile.zip


将数据压缩归档入一ZIP文件

类ZipOutputStream能够用来将数据压缩成一个ZIP文件。ZipOutputStream将数据写入ZIP格式的输出流。下面的步骤与创建一个ZIP文件相关。

1、第一步是创建一个ZipOutputStream对象,我们将要写入输出流的文件作为参数传给它。下面的代码演示了如何创建一个名为"myfigs.zip"的ZIP文件。
FileOutputStream dest = new
FileOutputStream("myfigs.zip");
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));

2、一但目标输出流创建后,下一步就是打开数据源文件。在这个例子中,源数据文件是指那些当前目录下的文件。命令list用来得到当前目录下文件列表:

File f = new File(".");
String files[] = f.list();
for (int i=0; i < files.length; i++) {System.out.println("Adding: "+files[i]);FileInputStream fi = new FileInputStream(files[i]);// create zip entry// add entries to ZIP file
}

注意:这个例程能够压缩当前目录下的所有文件。它不能处理子目录。作为一个练习,你可以修改例程3来处理子目录。

3、 为读出的数据创建一个ZIP条目列表:
ZipEntry entry = new ZipEntry(files[i]))

4、 在你将数据写入ZIP输出流之前,你必须使用putNextEntry方法将ZIP条目列表写入输出流:
out.putNextEntry(entry);

5、 将数据写入ZIP文件:
int count;
while((count = origin.read(data, 0, BUFFER)) != -1) {
out.write(data, 0, count);
}

6、 最后关闭所有的输入输出流:
origin.close();
out.close();
完整的程序代码如例程3所示。

Zip.java 
import java.io.*;
import java.util.zip.*;
public class Zip {static final int BUFFER = 2048;public static void main (String argv[]) {try {BufferedInputStream origin = null;FileOutputStream dest = new FileOutputStream("c:\\zip\\myfigs.zip");ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));//out.setMethod(ZipOutputStream.DEFLATED);byte data[] = new byte[BUFFER];// get a list of files from current directoryFile f = new File(".");String files[] = f.list();for (int i=0; i < files.length; i++) {System.out.println("Adding: "+files[i]);FileInputStream fi = new FileInputStream(files[i]);origin = new BufferedInputStream(fi, BUFFER);ZipEntry entry = new ZipEntry(files[i]);out.putNextEntry(entry);int count;while((count = origin.read(data, 0, BUFFER)) != -1) {out.write(data, 0, count);}origin.close();}out.close();} catch(Exception e) {e.printStackTrace();}}
}

注意: 条目列表可以以两种方式加入ZIP文件中,一种是压缩方式(DEFLATED),另一种是不压缩方式(STORED),系统默认的存储方式为压缩方式 (DEFLATED)。SetMethod方法可以用来设置它的存储方式。例如,设置存储方式为DEFLATED(压缩)应该这样做: out.setMethod(ZipOutputStream.DEFLATED) 设置存储方式为(不压缩)应该这样做: out.setMethod(ZipOutputStream.STORED)。



ZIP文件属性

类ZipEntry描述了存储在ZIP文件中的压缩文件。类中包含有多种方法可以用来设置和获得ZIP条目的信息。类ZipEntry是被 ZipFile和ZipInputStream使用来读取ZIP文件,ZipOutputStream来写入ZIP文件的。ZipEntry中最有用的一 些方法显示在下面的表格2中,并且有相应的描述。

方法签名描述
public String getComment()返回条目的注释, 没有返回null
public long getCompressedSize()返回条目压缩后的大小, 未知返回-1
public int getMethod()返回条目的压缩方式,没有指定返回 -1
public String getName()返回条目的名称
public long getSize()返回未被压缩的条目的大小,未知返回-1
public long getTime()返回条目的修改时间, 没有指定返回-1
public void setComment(String c)设置条目的注释
public void setMethod(int method)设置条目的压缩方式
public void setSize(long size)设置没有压缩的条目的大小
public void setTime(long time)设置条目的修改时间


求和校验

java.util.zip包中另外一些比较重要的类是Adler32和CRC32,它们实现了java.util.zip.Checksum接 口,并估算了压缩数据的校验和(checksum)。众所周知,在运算速度方面,Adler32算法比CRC32算法要有一定的优势;但在数据可信度方 面,CRC32算法则要更胜一筹。正所谓,"鱼与熊掌,不可兼得。",大家只好在不同的场合下,加以取舍了。GetValue方法可以用来获得当前的 checksum值,reset方法能够重新设置checksum为其缺省的值。

求和校验一般用来校验文件和信息是否正确的传送。举个例子,假设你想创建一个ZIP文件,然后将其传送到远程计算机上。当到达远程计算机后,你就可 以使用checksum检验在传输过程中文件是否发生错误。为了演示如何创建checksums,我们修改了例程1和例程3,在例程4和例程5中使用了两 个新类,一个是CheckedInputStream,另一个是CheckedOutputStream。(大家注意:这两段代码在压缩与解压缩过程中, 使用了同一种算法,求数据的checksum值。)

Zip.java 
import java.io.*;
import java.util.zip.*;
public class Zip {static final int BUFFER = 2048;public static void main (String argv[]) {try {BufferedInputStream origin = null;FileOutputStream dest = new FileOutputStream("c:\\zip\\myfigs.zip");CheckedOutputStream checksum = new CheckedOutputStream(dest, new Adler32());ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(checksum));//out.setMethod(ZipOutputStream.DEFLATED);byte data[] = new byte[BUFFER];// get a list of files from current directoryFile f = new File(".");String files[] = f.list();for (int i=0; i < files.length; i++) {System.out.println("Adding: "+files[i]);FileInputStream fi = new FileInputStream(files[i]);origin = new BufferedInputStream(fi, BUFFER);ZipEntry entry = new ZipEntry(files[i]);out.putNextEntry(entry);int count;while((count = origin.read(data, 0, BUFFER)) != -1) {out.write(data, 0, count);}origin.close();}out.close();System.out.println("checksum: "+checksum.getChecksum().getValue());} catch(Exception e) {e.printStackTrace();}}
}

UnZip.java 
import java.io.*;
import java.util.zip.*;
public class UnZip {public static void main (String argv[]) {try {final int BUFFER = 2048;BufferedOutputStream dest = null;FileInputStream fis = new FileInputStream(argv[0]);CheckedInputStream checksum = new CheckedInputStream(fis, new Adler32());ZipInputStream zis = new ZipInputStream(new BufferedInputStream(checksum));ZipEntry entry;while((entry = zis.getNextEntry()) != null) {System.out.println("Extracting: " +entry);int count;byte data[] = new byte[BUFFER];// write the files to the diskFileOutputStream fos = new FileOutputStream(entry.getName());dest = new BufferedOutputStream(fos, BUFFER);while ((count = zis.read(data, 0, BUFFER)) != -1) {dest.write(data, 0, count);}dest.flush();dest.close();}zis.close();System.out.println("Checksum: "+checksum.getChecksum().getValue());} catch(Exception e) {e.printStackTrace();}}
}

测试例程4和5,编译类文件并运行类Zip来创建一个压缩档案(程序会计算出checksum值并显示在屏幕上),然后运行UnZip类来解压缩这 个档案(屏幕上同样会打印出一个checksum值)。两个值必须完全相同,否则说明出错了。Checksums在数据校验方面非常有用。例如,你可以创 建一个ZIP文件,然后连同checksum值一同传递给你的朋友。你的朋友解压缩文件后,将生成的checksum值与你提供的作一比较,如果相同则说 明在传递过程中没有发生错误。

压缩对象

我们已经看到如何将文件中的数据压缩并将其归档。但如果你想压缩的数据不在文件中时,应该怎么办呢?假设有这样一个例子,你通过套接字 (socket)来传递一个大对象。为了提高应用程序的性能,你可能在通过网络开始传递前将数据压缩,然后在目的地将其解压缩。另外一个例子,我们假设你 想将一个对象用压缩格式存储在磁碟上,ZIP格式是基于记录方式的,不适合这项工作。GZIP更适合用来实现这种对单一数据流的操作。现在,我们来示例一 下,如果在写入磁碟前将数据压缩,并在读出时将数据解压缩。示例程序6是一个在单一JVM(java虚拟机)实现了Serializable接口的简单 类,我们想要串行化该类的实例。

Employee.java 
import java.io.*;
public class Employee implements Serializable {String name;int age;int salary;public Employee(String name, int age, int salary) {this.name = name;this.age = age;this.salary = salary;}public void print() {System.out.println("Record for: "+name);System.out.println("Name: "+name);System.out.println("Age: "+age);System.out.println("Salary: "+salary);}
}

现在,写另外一个类来创建两个从Employee类实例化而来的对象。示例程序7从Employee类创建了两个对象(sarah和sam)。然后将它们的状态以压缩的格式存储在一个文件中。

SaveEmployee.java 
import java.io.*;
import java.util.zip.*;
public class SaveEmployee {public static void main(String argv[]) throws Exception {// create some objectsEmployee sarah = new Employee("S. Jordan", 28, 56000);Employee sam = new Employee("S. McDonald", 29, 58000);// serialize the objects sarah and samFileOutputStream fos = new FileOutputStream("db");GZIPOutputStream gz = new GZIPOutputStream(fos);ObjectOutputStream oos = new ObjectOutputStream(gz);oos.writeObject(sarah);oos.writeObject(sam);oos.flush();oos.close();fos.close();}
}

现在,示例程序8中的ReadEmpolyee类是用来重新构建两个对象的状态。一但构建成功,就调用print方法将其打印出来。

ReadEmployee.java 
import java.io.*;
import java.util.zip.*;
public class ReadEmployee {public static void main(String argv[]) throws Exception{//deserialize objects sarah and samFileInputStream fis = new FileInputStream("db");GZIPInputStream gs = new GZIPInputStream(fis);ObjectInputStream ois = new ObjectInputStream(gs);Employee sarah = (Employee) ois.readObject();Employee sam = (Employee) ois.readObject();//print the records after reconstruction of statesarah.print();sam.print();ois.close();fis.close();}
}

同样的思想可以用于在网络间通过(socket)传输的大对象。下面的代码段示例了如何在客户/服务器之间实现大对象的压缩:

// write to client
GZIPOutputStream gzipout = new GZIPOutputStream(socket.getOutputStream());
ObjectOutputStream oos = new ObjectOutputStream(gzipout);
oos.writeObject(obj);
gzipos.finish();

下面的代码段显示了客户端从服务器端接收到数据后,如何将其解压:

// read from server
Socket socket = new Socket(remoteServerIP, PORT);
GZIPInputStream gzipin = new GZIPInputStream(socket.getInputStream());
ObjectInputStream ois = new ObjectInputStream(gzipin);
Object o = ois.readObject();

如何对JAR文件进行操作呢?

Java档案文件(JAR)格式是基于标准的ZIP文件格式,并附有可选择的文件清单列表。如果你想要在你我的应用程序中创建JAR文件或从JAR 文件中解压缩文件,可以使用java.util.jar包,它提供了读写JAR文件的类。使用java.util.jar包提供的类与本文所讲述的 java.util.zip包十分相似。所以你应该能够重新编写本文的源代码,如果你想使用java.util.jar包的话。

结束语

本文讨论了你可以在应用程序中使用的数据压缩与解压的应用程序接口,本文的示例程序演示了如何使用java.util.zip包来压缩数据与解压缩数据。现在你可以利用这个工具在你的应用程序中实现数据的压缩与解压了。

本文也说明了如何在络传输中实现数据的压缩与解压缩,以减少网络阻塞和增强你的客户/服务器模式应用程序的性能。在网络传输中实现数据的压缩,只有当传输的数据量达到成百上千字节时,你才会感觉到程序性能的提升,如果仅仅是传递一个字符串对象,对应用程序是没什么影响的。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/328860.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Asp.net Core基于MVC框架实现PostgreSQL操作

简单介绍 Asp.net Core最大的价值在于跨平台、跨平台、跨平台。重要的事情说三遍。但是目前毕竟是在开发初期&#xff0c;虽然推出了1.0.0 正式版&#xff0c;但是其实好多功能还没有完善。比方说编译时的一些文件编码问题&#xff0c;辅助工具Tools的一些Bug&#xff0c;还有一…

sql高级查询

子查询&#xff1a;是嵌套在select ,insert ,update ,delete语句或者其他的子查询中的查询语句。 一、一般的使用方式&#xff1a;select * from 表1 where 列 运算符 &#xff08;子查询&#xff09;注意&#xff1a;1.先执行子查询&#xff0c;在执行外查询&#xff08;主查询…

小米miui系统已停止服务器,小米两款机型停止 MIUI 更新,明天发布最终体验版固件...

原标题&#xff1a;小米两款机型停止 MIUI 更新&#xff0c;明天发布最终体验版固件11 月 21 日消息&#xff0c; MIUI 官方预告 MIUI 于 2018 年 11 月 22 日发布小米手机 5 、红米 Note 3 全网通的最后一个 MIUI 10 体验版/开发版 8.11.22 &#xff0c;两款机型将不再支持后续…

Java压缩技术(一) ZLib

转载自 Java压缩技术&#xff08;一&#xff09; ZLib 有关ZLib可参见官方主页 http://www.zlib.net/ ZLib可以简单的理解为压缩/解压缩算法&#xff0c;它与ZIP、RAR等归档算法有所不同&#xff0c;与bzip2比较接近。 压缩工具代码如下&#xff1a; Java代码 /** * 2009-9-9…

【送书活动】机器学习项目开发实战

出版时间 2016-08-01 定价&#xff1a;59元 作者&#xff1a; Mathias Brandewinder是Microsoft F# 最有价值专家&#xff08;MVP&#xff09;&#xff0c;住在加州旧金山&#xff0c;在那里他为Clear Lines Consulting工作。作为一名当之无愧的数学极客&#xff0c;他很早就对…

刀剑斗神传只显示11个服务器,与官方服务器互通 《刀剑斗神传》电脑版即将上线...

乱世江湖动作MMO手游《刀剑斗神传》将于12月29日开启公测&#xff0c;为方便玩家更好的体验游戏&#xff0c;游戏将推出电脑版&#xff0c;并与iOS、安卓的官方服务器实现数据互通。不管是在公交地铁上用手机&#xff0c;还是在自己温馨的小居室用电脑&#xff0c;你可以选择自…

深入wepy源码:wpy文件编译过程

转载自 深入wepy源码&#xff1a;wpy文件编译过程wepy 是腾讯开源的一款小程序框架&#xff0c;主要通过预编译的手段&#xff0c;让开发者采用类 Vue 风格开发。 让我们一起看看&#xff0c; wepy 是如何实现预编译的。先放上一张官网的流程图&#xff0c;后面的分析可以参考该…

sql事务、视图和索引

一、事务&#xff1a;1.概念&#xff1a;是单个逻辑单元执行的一系列操作&#xff08;一个事务中有多个sql语句&#xff09;&#xff0c;这个操作作为一个整体一起提交&#xff0c;要么执行&#xff0c;要么都不执行&#xff0c;多个事务操作是一个不可分割的逻辑单元。2.事务的…

qq空间说说服务器维护,如何解决QQ空间说说发表不了

如何解决QQ空间说说发表不了我的今天也是这种情况几个qq都发表不了&#xff0c;都不知道怎么办了&#xff0c;然后过一会儿又能发表了但是现在有发表不了了...是空间的系统问题吧&#xff01;还有啊就是不要加什么敏感词汇不然也发表不了一、如果您打开是提示“服务器忙&#x…

Win10上运行Docker

1. 前言 Docker最近推出了可以运行在Win10和Mac上的稳定版本&#xff0c;让我们赶紧来体验一下。 Docker发布Mac和Windows 的目标非常简单——开发者可以更加简单方便地在研发机器上使用Docker。下面是此次版本所改进的地方&#xff1a; 更快更可靠——在本地开发环境上&#x…

sql serve存储过程

存储过程一.概念:预先编译好的sql程序&#xff0c;可以包含&#xff1a;操作数据、变量、控制语句&#xff0c;增删改查操作都可以&#xff0c;存储过程是保存在数据库中 的一个对象。二.好处&#xff1a;1.安全性更高2.减少了网络流量3.提高速度&#xff0c;性能更高4.模…

JAVA数据库连接池实现

转载自 JAVA数据库连接池实现连接池的管理用了了享元模式&#xff0c;这里对连接池进行简单设计。 一、设计思路1.连接池配置属性DBbean&#xff1a;里面存放可以配置的一些属性2.连接池接口IConnectionPool&#xff1a;里面定义一些基本的获取连接的一些方法3.接口实现Conne…

在.NET开发面向Oracle数据库的应用程序

其实这个不是一个什么新的话题。但是之前在多次项目中&#xff0c;总是遇到大家针对Oracle数据库的访问时&#xff0c;会有各种各样的问题&#xff0c;最基本的就是要在客户端安装各种client&#xff0c;版本不一样的话还有各种问题。 静下心来看看&#xff0c;其实也没有那么难…

服务器ubuntu系统版本选型原则,系统集成 - 选择Ubuntu服务器版操作系统的六大理由_服务器应用_Linux公社-Linux系统门户网站...

二. 系统集成(1)集成现有的系统Ubuntu服务器版本用常用的身份认证方式和服务入口工具简单地集成企业现有的客户/服务器结构。我们都知道系统集成技术的重要性&#xff0c;这也是Ubuntu团队花费大量时间研究如何实现服务器与基础设施简单融合的原因。(2)简单的验证方式验证功能对…

sql serve基础

一、数据库登录名与数据库用户1.登录名登录服务器2.数据库用户访问具体数据库二者要建立映射关系二、数据库文件&#xff1a;1.主数据文件&#xff1a;*.mdf&#xff08;必须&#xff09;2.辅助数据文件&#xff1a;*.ndf(可选)3.日志文件&#xff1a;*.ldf&#xff08;必须&am…

sql基本操作语句

sql: 结构化查询语言T-SQL:sql server数据库中用的查询语言数据库对象操作&#xff1a;一、建库&#xff1a;二、建表&#xff1a;三、数据操作1.添加INSERT [INTO] 表名 (列列表) VALUES(值列表)a. 列列表和值列表一一对应&#xff08;顺序和个数&#xff09;b。可以为null的…

云服务器mqtt协议,云服务器mqtt协议

云服务器mqtt协议 内容精选换一换IPv6的使用&#xff0c;可以有效弥补IPv4网络地址资源有限的问题。如果当前云服务器使用IPv4&#xff0c;那么启用IPv6后&#xff0c;云服务器可在双栈模式下运行&#xff0c;即云服务器可以拥有两个不同版本的IP地址&#xff1a;IPv4地址和IPv…

常用的推荐算法解析

转载自 常用的推荐算法解析1. 前言随着互联网技术和社会化网络的发展&#xff0c;每天有大量包括博客&#xff0c;图片&#xff0c;视频&#xff0c;微博等等的信息发布到网上。传统的搜索技术已经不能满足用户对信息发现的需求&#xff0c;原因有多种&#xff0c;可能是用户…

一步一步封装自己的HtmlHelper组件:BootstrapHelper

前言&#xff1a;之前学习过很多的Bootstrap组件&#xff0c;博主就在脑海里构思&#xff1a;是否可以封装一套自己Bootstrap组件库呢。再加上看到MVC的Razor语法里面直接通过后台方法输出前端控件的方式&#xff0c;于是打算仿照HtmlHelper封装一套BootstrapHelper&#xff0c…

sql server简单查询

一、插入多行数据&#xff1a;1.insert into 。。。 select 从一个表中取出数据插入另一个已存在的表2.select into 从一个表中取出数据插入一个新表中3.insert into ()unionselect 常量列表 二、简单查询1. 查询所有行和列 SELECT * FROM 表名2.查询部分列 SELECT 列列…