【问题标题】:Don't quite understand how InputStream.read( byte[], int, int ) works不太明白 InputStream.read( byte[], int, int ) 的工作原理
【发布时间】:2012-07-24 14:11:37
【问题描述】:

我知道这是微不足道的,但对我来说没有意义。 Java 不能将指针/引用作为参数传递,但 read() 函数传递了一个 buffer into which the data is read,并且只返回一个 int 作为 the total number of bytes read into the buffer

我希望从此设备读取五个单独的字节,但是当我将缓冲区传递给函数并尝试访问它之后,它仍然是null。如果我打印出函数的返回值,它会给我int 5,这是预期的。但是如何访问实际放入缓冲区的数据呢?

这是JavaDocs....的链接。

编辑:

这是对 read 函数的原始调用。

public boolean onOptionsItemSelected( MenuItem item ) {
    switch( item.getItemId() ) {
    case R.id.connect:
        startActivityForResult( new Intent( this, DeviceList.class ), 1 );
        return true;
    case R.id.readTest:
        Log.i(TAG,  "Before write." );
        byte[] b = {'$'};
        for( int i = 0 ; i < 3 ; i++ ) {
            mService.write( b );
        }
        Log.i(TAG, "After write." );
        return true;

    case R.id.readData:
        byte[] c = mService.read( 5 );

        Toast.makeText(this, Integer.toString( mService.bytes ), Toast.LENGTH_LONG).show();
    default:
        return super.onContextItemSelected( item );
    }
}

注意,这个读取函数是在我的类中声明的一个函数,名为 BluetoothService。该类包含另一个名为 ConnectedThread 的类,它调用 InputStream 读取...

这是我的阅读功能....

public byte[] read( int length ) {
    Log.i( TAG, "Inside read." );
    ConnectedThread r;
    buffer = null;
    synchronized( this ) {
        if( mState != STATE_CONNECTED ) return null;
        r = mConnectedThread;
    }
    Log.i(TAG,  "Before run." );
    r.run( length );
    Log.i( TAG, "After run." );
    Log.i( TAG, Integer.toString( bytes ) );
    return buffer;

}

这里是 ConnectedThread 类,它自己调用 read....

/**
 * This thread runs during a connection with a remote device.
 * It handles all incoming and outgoing transmissions.
 */
private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket, String socketType) {
        Log.d(TAG, "create ConnectedThread: " + socketType);
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the BluetoothSocket input and output streams
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            Log.e(TAG, "temp sockets not created", e);
        }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run(int length) {
        Log.i(TAG, "BEGIN mConnectedThread");
        byte[] buffer = new byte[1024];


        // Keep listening to the InputStream while connected
        //while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer, 0, length);

                // Send the obtained bytes to the UI Activity
                mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "disconnected", e);
                connectionLost();
                // Start the service over to restart listening mode
                BluetoothService.this.start();
                //break;
            }
       // }
            Log.i(TAG, "MADE IT HERE" );
    }

    /**
     * Write to the connected OutStream.
     * @param buffer  The bytes to write
     */
    public void write(byte[] buffer) {
        try {
            mmOutStream.write(buffer);

            // Share the sent message back to the UI Activity
            mHandler.obtainMessage(MainMenu.MESSAGE_WRITE, -1, -1, buffer)
                    .sendToTarget();
        } catch (IOException e) {
            Log.e(TAG, "Exception during write", e);
        }
    }

    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "close() of connect socket failed", e);
        }
    }
}

【问题讨论】:

  • 你能提供一些代码来演示这个问题吗?
  • 你必须初始化数组。你不能一开始就让它为空。
  • 啊,谢谢你,可能是它。
  • 饥饿艺术家,发表答案,我会接受。愚蠢的我,但谢谢。
  • @JuiCe 完成。是的,它发生了:)

标签: java android inputstream


【解决方案1】:

Java 不能将指针/引用作为参数传递

可以。

像这样的基本误解让你非常困惑......

read(...)的使用方式应该是这样的:

byte[] buffer = new byte[42];
int nosRead = is.read(buffer, 0, buffer.length);

您分配一个缓冲区对象并将其作为参数传递给read 方法。从(在这种情况下)偏移量零开始读取字节并将其复制到缓冲区中。当方法调用返回时,它返回实际读取的字节数......并且字节在缓冲区中可供调用者处理。

如您所见,这依赖将字节数组引用作为参数传递给read方法。

【讨论】:

  • read如何确定下一次必须从最后读取的字节+1开始读取?这是代码public int read(byte[] buffer) throws IOException { return read(buffer, 0, buffer.length); },因为它通过 0 作为偏移量,所以我不明白它将如何确定下一步从哪里开始?
  • 您误解了read(...) 的作用。它正在读取字节>>进入read(byte[]) 的情况下,它开始将字节放入数组中偏移量为零的位置......因为这是我们告诉它要做的。
  • 我知道read 正在将字节放入数组中。参考public int read(byte[] buffer, int byteOffset, int byteCount)的实现中的行 buffer[byteOffset + i] = (byte) c; 这就是我们通常如何读取流while((count = is.read(data)) != -1) { total += count; fos.write(data, 0, count); } 在每次迭代中它读取流并放入byte[] 中的字节,并且在下一次迭代中它会执行相同的操作。 1/2
  • 我不明白read 怎么知道它已经读取了一些字节,现在它必须从下一个未读字节开始。假设它在第一次迭代中读取 10 个字节,在下一次迭代中它必须从没有 11 个字节开始。它在代码中的哪个位置被确定。 2/2
  • 在幕后,输入流跟踪它已缓冲的未读字节。请记住,InputStream 实际上是一个抽象类。 (例如)从文件或标准输入读取的输入流的实际读取方法正在执行其他操作。例如,如果您查看 GrepCode 中的代码,您可以找到发生这种情况的 InputStream 的相关后代类。在某些情况下,跟踪您在流中的位置实际上是由操作系统内核完成的!
【解决方案2】:

你必须初始化数组,否则它将继续保持为空。

【讨论】:

    【解决方案3】:

    也许您的 C 背景让您在正确调用 read() 时感到困惑。 read(byte[]) 和 read(byte[] b, int offset, int len) 不是返回一个数组或使用指向指针的指针创建一个数组,而是期望一个实际的字节数组(在后一种形式中,大小更大或等于参数列表中的 offset+len)。假设方法返回值x,则数组中会定义从offsetoffset+x-1的数组元素(除非返回-1,表示一个EOF)。

    【讨论】:

    • 实际上这是 Java 的一部分,它非常紧密地反映了底层 C API。 C stdlib 避免为您分配/释放内存。 (IIRC 有一些系统调用违反了这个约定。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-31
    • 1970-01-01
    • 2014-02-28
    • 2014-04-23
    • 1970-01-01
    • 1970-01-01
    • 2010-10-30
    相关资源
    最近更新 更多