发布(未测试)代码片段,它应该给你基本的想法:
/**
* Implementors of this interface should only convert current row to byte array and return it.
*
* @author yura
*/
public interface RowToByteArrayConverter {
byte[] rowToByteArray(ResultSet resultSet);
}
public class ResultSetAsInputStream extends InputStream {
private final RowToByteArrayConverter converter;
private final PreparedStatement statement;
private final ResultSet resultSet;
private byte[] buffer;
private int position;
public ResultSetAsInputStream(final RowToByteArrayConverter converter, final Connection connection, final String sql, final Object... parameters) throws SQLException {
this.converter = converter;
statement = createStatement(connection, sql, parameters);
resultSet = statement.executeQuery();
}
private static PreparedStatement createStatement(final Connection connection, final String sql, final Object[] parameters) {
// PreparedStatement should be created here from passed connection, sql and parameters
return null;
}
@Override
public int read() throws IOException {
try {
if(buffer == null) {
// first call of read method
if(!resultSet.next()) {
return -1; // no rows - empty input stream
} else {
buffer = converter.rowToByteArray(resultSet);
position = 0;
return buffer[position++] & (0xff);
}
} else {
// not first call of read method
if(position < buffer.length) {
// buffer already has some data in, which hasn't been read yet - returning it
return buffer[position++] & (0xff);
} else {
// all data from buffer was read - checking whether there is next row and re-filling buffer
if(!resultSet.next()) {
return -1; // the buffer was read to the end and there is no rows - end of input stream
} else {
// there is next row - converting it to byte array and re-filling buffer
buffer = converter.rowToByteArray(resultSet);
position = 0;
return buffer[position++] & (0xff);
}
}
}
} catch(final SQLException ex) {
throw new IOException(ex);
}
}
@Override
public void close() throws IOException {
try {
statement.close();
} catch(final SQLException ex) {
throw new IOException(ex);
}
}
}
这是非常直接的实现,可以通过以下方式进行改进:
- 可以删除 read 方法中 if 和 else 之间的代码重复 - 它只是为了澄清而发布
- 而不是为每一行重新创建字节数组缓冲区(
new byte[]
操作成本很高),可以实现更复杂的逻辑来使用字节数组缓冲区,它只初始化一次然后重新填充。然后应该更改RowToByteArrayConverter.rowToByteArray
方法的签名,int fillByteArrayFromRow(ResultSet rs, byte[] array)
该签名应该返回填充的字节数并填充传递的字节数组。
因为字节数组包含它可以包含的有符号字节-1
(实际上255
是无符号字节),因此表明流的不正确结束,所以& (0xff)
用于将有符号字节转换为无符号字节作为整数值。具体参考Java如何将int转换为byte?.
另请注意,如果网络传输速度较慢,这可能会长时间保持打开的结果集,从而给数据库带来问题。
希望这可以帮助 ...