Проблема связана с движком таблицы, который MyISAM
. Транзакция способна откат после того, как я изменил движок на InnoDB
.
Настройка hibernate.dialect
на org.hibernate.dialect.MySQLInnoDBDialect
гарантирует создание таблицы с InnoDB
в будущем.
Вот довольно простая реализация, которая запускает PropertyChangeEvent
s при чтении дополнительных байтов. Некоторые предостережения:
mark
или reset
, хотя их было бы легко добавить. Код:
public class ProgressInputStream extends FilterInputStream {
private final PropertyChangeSupport propertyChangeSupport;
private final long maxNumBytes;
private volatile long totalNumBytesRead;
public ProgressInputStream(InputStream in, long maxNumBytes) {
super(in);
this.propertyChangeSupport = new PropertyChangeSupport(this);
this.maxNumBytes = maxNumBytes;
}
public long getMaxNumBytes() {
return maxNumBytes;
}
public long getTotalNumBytesRead() {
return totalNumBytesRead;
}
public void addPropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.removePropertyChangeListener(l);
}
@Override
public int read() throws IOException {
int b = super.read();
updateProgress(1);
return b;
}
@Override
public int read(byte[] b) throws IOException {
return (int)updateProgress(super.read(b));
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return (int)updateProgress(super.read(b, off, len));
}
@Override
public long skip(long n) throws IOException {
return updateProgress(super.skip(n));
}
@Override
public void mark(int readlimit) {
throw new UnsupportedOperationException();
}
@Override
public void reset() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public boolean markSupported() {
return false;
}
private long updateProgress(long numBytesRead) {
if (numBytesRead > 0) {
long oldTotalNumBytesRead = this.totalNumBytesRead;
this.totalNumBytesRead += numBytesRead;
propertyChangeSupport.firePropertyChange("totalNumBytesRead", oldTotalNumBytesRead, this.totalNumBytesRead);
}
return numBytesRead;
}
}
Если вы создаете приложение GUI, всегда есть ProgressMonitorInputStream . Если нет никакого GUI, связанного с оберткой InputStream
в том, как вы описываете, это не проблема и занимает меньше времени, чем сообщение здесь.
ProgressMonitor
. Обертка InputStream
займет меньше времени, чем вопрос, но я никогда не узнаю, есть ли у кого-то лучшая идея.
– David Moles
27 August 2009 в 09:12
Пакет Guava com.google.common.io
может помочь вам немного. Следующее - нескомпилированное и непроверенное, но должно поместить вас на правильный путь.
long total = file1.length();
long progress = 0;
final OutputStream out = new FileOutputStream(file2);
boolean success = false;
try {
ByteStreams.readBytes(Files.newInputStreamSupplier(file1),
new ByteProcessor<Void>() {
public boolean processBytes(byte[] buffer, int offset, int length)
throws IOException {
out.write(buffer, offset, length);
progress += length;
updateProgressBar((double) progress / total);
// or only update it periodically, if you prefer
}
public Void getResult() {
return null;
}
});
success = true;
} finally {
Closeables.close(out, !success);
}
Это может показаться большим количеством кода, но я считаю, что это будет наименее, с чего вам это удастся. (обратите внимание, что другие ответы на этот вопрос не дают примеров кода complete , поэтому их сложно сравнивать).
Чтобы выполнить ответ, заданный @Kevin Bourillion, он также может быть применен к сетевому контенту, используя этот метод (который предотвращает чтение потока дважды: один для размера и один для контента):
final HttpURLConnection httpURLConnection = (HttpURLConnection) new URL( url ).openConnection();
InputSupplier< InputStream > supplier = new InputSupplier< InputStream >() {
public InputStream getInput() throws IOException {
return httpURLConnection.getInputStream();
}
};
long total = httpURLConnection.getContentLength();
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteStreams.readBytes( supplier, new ProgressByteProcessor( bos, total ) );
Где ProgressByteProcessor является внутренним классом:
public class ProgressByteProcessor implements ByteProcessor< Void > {
private OutputStream bos;
private long progress;
private long total;
public ProgressByteProcessor( OutputStream bos, long total ) {
this.bos = bos;
this.total = total;
}
public boolean processBytes( byte[] buffer, int offset, int length ) throws IOException {
bos.write( buffer, offset, length );
progress += length - offset;
publishProgress( (float) progress / total );
return true;
}
public Void getResult() {
return null;
}
}
Ответ Адамски работает, но есть небольшая ошибка. Переопределенный метод read(byte[] b)
вызывает метод read(byte[] b, int off, int len)
через суперкласс. Таким образом, updateProgress(long numBytesRead)
вызывается дважды для каждого действия чтения, и вы получаете numBytesRead
, который в два раза больше размера файла после того, как весь файл был прочитан.
Не отменяет метод read(byte[] b)
, решает проблему.
skip()
. :) – David Moles 27 August 2009 в 09:24super.read()
не возвращает отрицательный (конец данных). – PhoneixS 24 February 2014 в 12:59read(byte[]b)
должна быть толькоreturn read(b, 0, b.length);
( без обновления прогресса). В текущей реализации вызовread(byte[]b)
заставляет считанные байты считаться дважды i>, потому что реализацияFilterInputStream#read(byte[]b)
прямо вызываетread(byte[]b,int off,int len)
. – Marco13 12 June 2016 в 23:31