InputStream возвращает неожиданное -1 / пусто

1

Кажется, я вижу постоянный неожиданный конец моего файла. Мой файл содержит сначала пару строк, затем байтовые данные.

Файл содержит несколько разделенных строк, которые мой код читает правильно.

Однако, когда я начинаю читать байты, он ничего не возвращает. Я почти уверен, что это связано со мной с помощью Читателей. Прочитал ли BufferedReader весь поток? Если да, то как я могу это решить?

Я проверил файл, и он содержит много данных после строк.

InputStreamReader is = new InputStreamReader(in);
BufferedReader br = new BufferedReader(is);
String line;
{
    line = br.readLine();
    String split[] = line.split(" ");

    if (!split[0].equals("#binvox")) {
        ErrorHandler.log("Not a binvox file");
        return false;
    }
    ErrorHandler.log("Binvox version: " + split[1]);
}

ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead, cnt = 0;
byte[] data = new byte[16384];

while ((nRead = in.read(data, 0, data.length)) != -1) {
    buffer.write(data, 0, nRead);
    cnt += nRead;
}

buffer.flush();
// cnt is always 0

Формат binvox следующий:

#binvox 1
dim 64 40 32
translate -3 0 -2
scale 6.434
data
[byte data]

Я в основном пытаюсь преобразовать следующий код C в Java: http://www.cs.princeton.edu/~min/binvox/read_binvox.html

  • 0
    Содержит ли файл двоичные или текстовые данные после маркера #binvox ?
  • 0
    Я добавил формат заголовка binvox. Вот эквивалент C: cs.princeton.edu/~min/binvox/read_binvox.html
Теги:

5 ответов

0
Лучший ответ

Я видел код другого, который решил именно это.

Он использовал DataInputStream, который может выполнять readLine (хотя и устаревший) и readByte.

1

Поскольку icza написал alraedy, вы не можете создать InputStream и BufferedReader и пользователей обоих. BufferedReader будет считывать из InputStream столько, сколько он хочет, а затем вы не можете получить доступ к своим данным из InputStream.

У вас есть несколько способов исправить это:

  1. Не используйте Reader. Прочитайте сами байты из InputStream и вызовите на нем new String(bytes).
  2. Храните данные в кодировке (например, Base64). Закодированные данные могут считываться из Reader. Я бы рекомендовал это решение. Это будет выглядеть так:
public byte[] readBytes (Reader in) throws IOException
{
    String base64 = in.readLine(); // Note that a Base64-representation never contains \n
    byte[] data = Base64.getDecoder().decode(base64);
    return data
}
  • 0
    Разве я не могу просто получить данные типа char и преобразовать их в байты?
  • 0
    @RobotRock Это именно то, что я пишу там, за исключением того, что оно закодировано в base64. Если он не закодирован (независимо от того, как), вы не можете обмениваться файлами с разных платформ, так как они будут иметь разные кодировки
Показать ещё 2 комментария
1

Для чтения всей String вы должны это сделать:

ArrayList<String> lines = new ArrayList<String>();
while ((line = br.readLine();) != null) {
    lines.add(line);
}

а затем вы можете сделать цикл, чтобы разделить каждую строку, или просто сделать то, что вам нужно сделать в течение цикла.

0

Я рекомендую создать BinvoxDetectorStream который предварительно считывает некоторые байты

public class BinvoxDetectorStream extends InputStream {

    private InputStream orig;
    private byte[] buffer = new byte[4096];
    private int buflen;
    private int bufpos = 0;


    public BinvoxDetectorStream(InputStream in) {
        this.orig = new BufferedInputStream(in);
        this.buflen = orig.read(this.buffer, 0, this.buffer.length);
    }

    public BinvoxInfo getBinvoxVersion() {
        // creating a reader for the buffered bytes, to read a line, and compare the header
        ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
        BufferedReader rdr = new BufferedReader(new InputStreamReader(bais)));
        String line = rdr.readLine();
        String split[] = line.split(" ");
        if (split[0].equals("#binvox")) {
            BinvoxInfo info = new BinvoxInfo();
            info.version = split[1];
            split = rdr.readLine().split(" ");

            [... parse all properties ...]

            // seek for "data\r\n" in the buffered data
            while(!(bufpos>=6 &&
                    buffer[bufpos-6] == 'd' &&
                    buffer[bufpos-5] == 'a' && 
                    buffer[bufpos-4] == 't' && 
                    buffer[bufpos-3] == 'a' && 
                    buffer[bufpos-2] == '\r' && 
                    buffer[bufpos-1] == '\n') ) {
                bufpos++;
            }
            return info;

        }
        return null;
    }

    @Override
    public int read() throws IOException {
        if(bufpos < buflen) {
             return buffer[bufpos++];
        }
        return orig.read();
    }
}

Затем вы можете обнаружить версию Binvox, не касаясь исходного потока:

BinvoxDetectorStream bds = new BinvoxDetectorStream(in);
BinvoxInfo info = bds.getBinvoxInfo();
if (info == null) {
    return false;
}
...
[moving bytes in the usual way, but using bds!!! ]

Таким образом, мы сохраняем исходные байты в bds, поэтому мы сможем скопировать его позже.

0

Вы не можете обернуть InputStream в BufferedReader и использовать оба.

В качестве подсказок названия BufferedReader может читать вперед и буферизовать данные из базового InputStream который тогда не будет доступен при прямом чтении из базового InputStream.

Предлагаемое решение - не смешивать текстовые и двоичные данные в одном файле. Они должны храниться в двух отдельных файлах, а затем их можно читать отдельно. Если оставшиеся данные не являются бинарными, вы не должны читать их через InputStream но через свою обертку BufferedReader же, как вы читаете первые строки.

  • 0
    Хорошо, как я и предполагал. Как мне решить это тогда?
  • 0
    Проблема в том, что вы смешиваете текстовые данные и двоичные данные в одном файле. Ты не должен этого делать. А если нет, вы можете прочитать их отдельно.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню