Buffering using Array and reading parts of it.
Hi,
Excuse me, but I wasn't able to form the subject of the title very good. Now I will explain you the problem better: I have a file splitted in many parts (for example 100). In order to join this file I have to read all the parts, one by one, and update an array, to which every part is added. Of course this takes time, and the user is usually unpatient. So I want to at 1/4 of this "buffering" to start showing the file - to start outputing the first parts of the array, while the other parts continue to be added. Any ideas?
> Of course this> takes time, and the user is usually unpatient. How much time?How big are the files?How are you reading the files?How are you presenting the content of the files to the user?
Well, let's say that the parts are 64000bytes (array with size 64000), and you have 50 parts, then the for-loop which should read the array 50 times * 64000bytes - it takes around 5minutes for 2MB file. The size of files is every time different - once will be 2, once will be 7MB or even 30MB. The files are stored in 64KB-parts in the filesystem and I am using bufferedinputstream which reads data to a byte[] with size 64000, and then add the contents of this byte[] to a bigger array.
> Well, let's say that the parts are 64000bytes (array
> with size 64000), and you have 50 parts, then the
> for-loop which should read the array 50 times *
> 64000bytes - it takes around 5minutes for 2MB file.
Then you have serious problem with your code because it should take nothing like that long! I load and parse a 27 MByte map file in a couple of seconds.
> The size of files is every time different - once will
> be 2, once will be 7MB or even 30MB. The files are
> stored in 64KB-parts in the filesystem and I am using
> bufferedinputstream which reads data to a byte[] with
> size 64000, and then add the contents of this byte[]
> to a bigger array.
Post your code!
This is an application for a smartphone device, but the problem is in the basics.
Status.show("Starting playback...", 300);
String sSongName = (String)lfldc.get(lfld, lfld.getSelectedIndex());
currPlaying = sSongName;
RecordStore rs = null;
byte[] data = new byte[0]; //main which will store all data
byte[] temp = new byte[0]; //temporary one for data
byte[] buffer = new byte[64000]; // we will read from the filesystem here
int y = 0;
rs = RecordStore.openRecordStore("Mp3Player:" + sSongName, false); //open file
data = rs.getRecord(1);
rs.closeRecordStore();
int iFileParts = Integer.parseInt(new String(data), 10);
/******* HERE IS THE PROBLEMATIC FOR-LOOP ********/
for(int i = 1; i <= iFileParts; i++) {
Status.show("Buffering! Please wait ..." + i + "/" + iFileParts, 500);
rs = RecordStore.openRecordStore("Mp3Player:" + sSongName + ":" + i, false); //open file
buffer = rs.getRecord(1); //get file data
rs.closeRecordStore();
temp = data; //save old data
data = new byte[temp.length + 64000]; //add 64000bytes to length
for(int z = 0; z < temp.length; z++)
data[z] = temp[z]; //return back old data
for(int z = temp.length; z < data.length; z++) {
if(y < buffer.length) {
data[z] = buffer[y]; //add new data
y++;
}
else break;
}
y = 0;
}
/*********END OF THE LOOP ***********/
p = javax.microedition.media.Manager.createPlayer(new ByteArrayInputStream(data), "audio/mpeg"); //create player
p.realize();
p.prefetch();
vc = (VolumeControl)p.getControl("VolumeControl");
p.addPlayerListener(new MusicListener());
vc.setLevel(preferredVolume);
p.start(); //play
Ok, I've managed to speed up the process a little bit - removed all the for-loops which extended the data array, and placed the follwoing call: System.arraycopy(Object,int, Object, int, int)
So it is not actually a File but a databse record! I do just this to store large documents in a database. My extraction code is
public void extract(int fileID, OutputStream os) throws SQLException, IOException
{
String extractFileSQL = "SELECT file_content FROM FILE_CONTENT where file_id = ? ORDER BY ID";
PreparedStatement stmnt = connection_.prepareStatement(extractFileSQL);
stmnt.setInt(1, fileID);
ResultSet rs = stmnt.executeQuery();
int len = 0;
int index = 0;
while (rs.next())
{
index++;
InputStream is = rs.getBinaryStream(1);
IOCopy.copyInputStreamToOutputStream(is, os);
is.close();
}
rs.close();
}
This load 64MByte from a MySQL database and writes it to a file in about a second.
The IOCopy.copyInputStreamToOutputStream() method is
static public OutputStream copyInputStreamToOutputStream(InputStream istrm, OutputStream ostrm, int bufferLength) throws IOException
{
if (bufferLength < 128)
bufferLength = 128;
else if (bufferLength > 65536)
bufferLength = 65536;
byte[] buffer = new byte[bufferLength];
for (int bytesRead = 0; (bytesRead = istrm.read(buffer)) >= 0;)
{
ostrm.write(buffer, 0, bytesRead);
}
ostrm.flush();
return ostrm;
}
but I wrote this some time age before NIO so it could be made faster.
You can write the output into a ByteArrayOutputSteam and get the bytes from it. This will save a load of copying.
I also use this to to write database content to my home grown MP3 and OGG player and I don't even have to buffer it. I just write the byte straight to the the MP3/OGG bit streams.
For all who want to see the answer, here's how I speeded up the process a lot:
Status.show("Starting playback...", 300);
String sSongName = (String)lfldc.get(lfld, lfld.getSelectedIndex());
currPlaying = sSongName;
RecordStore rs = null;
byte[] data = new byte[0]; //main which will store all data
byte[] buffer = new byte[64000]; // we will read from the filesystem here
rs = RecordStore.openRecordStore("Mp3Player:" + sSongName, false); //open file
data = rs.getRecord(1);
rs.closeRecordStore();
int iFileParts = Integer.parseInt(new String(data), 10);
data = new byte[iFileParts * 64000];
int currPos = 0;
/******* HERE IS THE FOR-LOOP ********/
for(int i = 1; i <= iFileParts; i++) {
Status.show("Buffering! Please wait ..." + i + "/" + iFileParts, 500);
rs = RecordStore.openRecordStore("Mp3Player:" + sSongName + ":" + i, false); //open file
buffer = rs.getRecord(1); //get file data
rs.closeRecordStore();
System.arraycopy(buffer,0,data,currPos,buffer.length);
currPos += buffer.length;
}
/*********END OF THE LOOP ***********/
p = javax.microedition.media.Manager.createPlayer(new ByteArrayInputStream(data), "audio/mpeg"); //create player
p.realize();
p.prefetch();
vc = (VolumeControl)p.getControl("VolumeControl");
p.addPlayerListener(new MusicListener());
vc.setLevel(preferredVolume);
p.start(); //play
@sabre150: Thanks a lot, man! You indeed helped me, I will use parts of your code when I upload the files to the "database" as you call it! :) ;)
