这是导致错误的图像
我有这个问题,我尝试了我所知道的一切,但都没有成功。我试图通过套接字将多个图像(一次一个图像)从数据库发送到客户端应用程序,有时一切都很好,但有时它会声明这个"无效的JPEG文件结构:两个SOI标记"错误?
客户端:
for(User user : users){
int cmpt=0;
byteToread =in.readInt();
bytesOut=new ByteArrayOutputStream();
bos = new BufferedOutputStream(bytesOut);
while (byteToread >cmpt) {
cmpt = in.read(dataEntre);
bos.write(dataEntre, 0, cmpt);
bos.flush();
byteToread-=cmpt;
}
BufferedImage bi = ImageIO.read(new ByteArrayInputStream(bytesOut.toByteArray()));
user.setPhoto(new ImageIcon(bi));
System.out.println("------------------end");
}
bos.close();
bytesOut.close();
服务器端:
InputStream input =null;
Statement myStmt = null;
ResultSet myRs = null;
BufferedInputStream bis=null;
try {
myStmt = Conn.createStatement();
myRs = myStmt.executeQuery("select Photo from users order by Name");
byte[] buffer;
int k =1;
while (myRs.next()) {
input=myRs.getBinaryStream("Photo");
bis = new BufferedInputStream(input);
buffer = new byte[1024];
try {
int byteToread = 0;
int cmpt=0;
byteToread=input.available();
out.writeInt(byteToread);
out.flush();
int i=0;
while (byteToread>cmpt) {
cmpt = bis.read(buffer);
out.write(buffer, 0, cmpt);
out.flush();
byteToread -= cmpt;
}
} catch (IOException ex) {
return ;
}
}
不要使用available()
作为输入长度的度量。Javadoc中对此有一个特别的警告。这不是它的目的。
你的复制循环应该是这样的:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
第一件事:你遇到的错误:
每个JPEG图像总是以StartOfImage标记开始,十六进制为:FFD8您正在创建的缓冲区中的字节包含此SOI标记两次。很可能您得到的是图像1的字节+图像2的一些字节,特别是包含第二个图像的标记的起始字节。
我认为你在这里犯了一个错误:
byteToread =in.readInt();
bytesOut=new ByteArrayOutputStream();
bos = new BufferedOutputStream(bytesOut);
while (byteToread >cmpt) {
cmpt = in.read(dataEntre);
bos.write(dataEntre, 0, cmpt);
bos.flush();
byteToread-=cmpt;
}
举个例子,您总共有100个字节。出于某种原因,您将以50、30、20个字节为一组来读取这100个字节。
这将给出以下内容:
iteration 1:
during while:
bytesToRead: 100
cmpt: 0
at the end of the loop:
bytesToRead: 50
cmpt: 50
iteration 2:
during while:
bytesToRead: 50
cmpt: 50
此时,byteToRead(50)不大于cmpt(50),因此循环在不写入最后50个字节时结束。
你可能需要这样的东西:
bytesToread = in.readInt();
bytesOut=new ByteArrayOutputStream();
bos = new BufferedOutputStream(bytesOut);
while (byteToread > 0) {
cmpt = in.read(dataEntre);
bos.write(dataEntre, 0, cmpt);
bos.flush();
byteToread-=cmpt;
}
可能对于小图像,您可以一次性读取全部字节数(尽管这不能保证,但很可能)。如果发生这种情况,那么您将在一次迭代中完成,并且永远不会遇到问题。但是,对于较大的图像,您可能会担心读取的最后一个块会导致您丢失图像末尾的一些字节。这可能会给带来麻烦
第二个问题可能是(服务器端)
byteToread=input.available();
您从数据库获得的结果集可能还没有所有可用的字节。
来自available()的文档
请注意,虽然InputStream的某些实现将返回流中的总字节数,但许多实现不会返回。使用此方法的返回值来分配用于保存此流中所有数据的缓冲区是不正确的。
从我所看到的情况来看(根据我的测试程序),出现了以下情况:
1:您得到的是image1(比如200字节)。2:将长度(200)写入输出流3:您向输出流写入的字节数少于200(比如150)。(由于逻辑错误)4:你得到的是image2(比如300字节)5:将长度(300)写入输出流6:将N个字节写入输出流。
当你阅读时
1:你读了image1.length。这会给你200。2:你读了200个字节。因为您只从图像1中写入了150个字节,这意味着您从图像1获得了150字节,图像2的长度,然后从图像2获得了46个字节。
这将导致您认为是图像1的字节,其中包含jpg的2个标头。(图像2的前46个字节将包含图像2的标题)
我认为你需要附加你的调试器,然后逐步完成,找出其他问题。给出的另一个答案显示了如何循环并正确计算读取的字节数。可能还有更多的问题。