有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

为什么Java不能从InputStream正确地重新创建此映像?

我已经从各个角度考虑过了。。。问题是,我最终编写了完美的字节数,文件非常相似,但有些字节不同。我在Scite中打开了Java生成的文件以及原始文件,尽管它们很接近,但它们并不相同。有办法解决这个问题吗?我尝试了一切可能的方法——我使用了不同的包装器、读取器、写入器和不同的方法来获取字节数组(或将其作为字符——两者都尝试过)并将其生成文件

测试中的图像位于http://www.google.com/images/srpr/nav_logo13.png。代码如下:

import java.awt.Image;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.imageio.ImageIO;

public class ImgExample
{

    private String address = "http://www.google.com";
    /**
     * Returns a 3 dimensional array that holds the RGB values of each pixel at the position of the current
     * webcam picture. For example, getPicture()[1][2][3] is the pixel at (2,1) and the BLUE value.
     * [row][col][0] is alpha
     * [row][col][1] is red
     * [row][col][2] is green
     * [row][col][3] is blue
     */
    public int[][][] getPicture()
    {
        Image camera = null;
        try {
            int maxChars = 35000;
            //The image in question is 28,736 bytes, but I want to make sure it's bigger
            //for testing purposes as in my case, it's an image stream so it's unpredictable
            byte[] buffer = new byte[maxChars];
            //create the connection
            HttpURLConnection conn = (HttpURLConnection)(new URL(this.address+"/images/srpr/nav_logo13.png")).openConnection();
            conn.setUseCaches(false);
            //wrap a buffer around our input stream
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            int bytesRead = 0;
            while ( bytesRead < maxChars && reader.ready() )
            {
                //reader.read returns an int - I'm assuming this is okay?
                buffer[bytesRead] = (byte)reader.read();
                bytesRead++;
                if ( !reader.ready() )
                {
                    //This is here to make sure the stream has time to download the next segment
                    Thread.sleep(10);
                }
            }
            reader.close();

            //Great, write out the file for viewing
            File writeOutFile = new File("testgoog.png");
            if ( writeOutFile.exists() )
            {
                writeOutFile.delete();
                writeOutFile.createNewFile();
            }
            FileOutputStream fout = new FileOutputStream(writeOutFile, false);
            //FileWriter fout = new FileWriter(writeOutFile, false);
            //needed to make sure I was actually reading 100% of the file in question
            System.out.println("Bytes read = "+bytesRead);
            //write out the byte buffer from the first byte to the end of all the chars read
            fout.write(buffer, 0, bytesRead);
            fout.flush();
            fout.close();

            //Finally use a byte stream to create an image
            ByteArrayInputStream byteImgStream = new ByteArrayInputStream(buffer);
            camera = ImageIO.read(byteImgStream);
            byteImgStream.close();
        } catch ( Exception e ) { e.printStackTrace(); }
        return ImgExample.imageToPixels(camera);
    }

    public static int[][][] imageToPixels (Image image)
    {
        //there's a bunch of code here that works in the real program, no worries
        //it creates a 3d arr that goes [x][y][alpha, r, g, b val]
        //e.g. imageToPixels(camera)[1][2][3] gives the pixel's blue value for row 1 col 2
        return new int[][][]{{{-1,-1,-1}}};
    }

    public static void main(String[] args)
    {
        ImgExample ex = new ImgExample();
        ex.getPicture();
    }
}

共 (4) 个答案

  1. # 1 楼答案

    我认为您的问题是您正在使用InputStreamReader。来自javadocs

    An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset. The charset that it uses may be specified by name or may be given explicitly, or the platform's default charset may be accepted.
    

    您不希望转换为字符流

  2. # 2 楼答案

    您也不应该像这样使用ready()。你只是在浪费时间和睡眠。read()将一直阻止,直到数据到达,并且它将阻止正确的时间长度,而不是任意猜测。Java中的规范复制循环如下所示:

    int count;
    byte[] buffer; // whatever size you like
    while ((count = in.read(buffer)) > 0)
    {
      out.write(buffer, 0, count);
    }
    
  3. # 3 楼答案

    BufferedReader用于读取字符流,而不是字节/二进制流

    缓冲读取器。read()以0到65535范围内的整数形式返回读取的字符。这可能会截断字节值大于65535的任何二进制数据

    我认为您希望直接使用InputStream.read(),而不是用BufferedReader/InputStreamReader包装

    最后,与问题无关,但是如果您打开一个FileOutputStream以append=false,那么删除任何已经存在的文件实际上没有任何意义——append=false也会做同样的事情

  4. # 4 楼答案

    我所看到的问题是,您正在使用^{}s。在Java中,Readers用于处理字符流,而不是二进制流,它所做的字符转换很可能是更改您的字节的原因

    相反,您应该直接从^{}read()InputStream的{}将阻塞,直到数据可用,但在到达流的末尾时返回-1

    编辑:您还可以将InputStream包装为^{}