How to load object data saved in Unity C#? - unity3d

I want to create a universal storage system in Unity C#.
What my code not work? Object can't define or did I write wrong?
If not use functions from SaveExtensions then everything will work.
https://drive.google.com/open?id=1hLFRB2rHj7XcJT6et7TskEa7sLwdmJhP

While your saving works the problem is in your Load method.
obj = bf.Deserialize(fs);
this change is only applied locally inside the method but it doesn't actually change the value of the calling ex in
ex.Load("asd", ".dat", SaveExtension.Path.PersistentDataPath);
Unfortuanetly ref and out are not allowed in extension methods so one workaround might be giving the method a proper return value instead (I also made some changes to the rest of your code):
[System.Serializable]
internal static class SaveExtension
{
public enum Path
{
PersistentDataPath,
TemporaryCachePath
}
public static void Save(this object obj, string name, string type, Path path)
{
var pathString = "";
switch (path)
{
case Path.PersistentDataPath:
pathString = Application.persistentDataPath;
break;
case Path.TemporaryCachePath:
pathString = Application.temporaryCachePath;
break;
}
// There is no need to create the file
// in a dedicated if block since it will be created anyway
// Additionally: You did only create a new file but due to
// if-else you didn't write to it the first time
Debug.Log("[SaveSystem]: File " + name + type + " already exist!");
Debug.Log("[SaveSystem]: Location: " + pathString + "/" + name + type);
var bf = new BinaryFormatter();
using (var fs = File.Open(pathString + "/" + name + type, FileMode.Open, FileAccess.Write))
{
bf.Serialize(fs, obj);
}
Debug.Log("[SaveSystem]: Object succesful serialized!");
}
public static T Load<T>(this T obj, string name, string type, Path path)
{
var output = default(T);
var pathString = "";
switch (path)
{
case Path.PersistentDataPath:
pathString = Application.persistentDataPath;
break;
case Path.TemporaryCachePath:
pathString = Application.temporaryCachePath;
break;
}
if (!File.Exists(pathString + "/" + name + type))
{
Debug.LogFormat("File " + pathString + "/" + name + type + " not found! returning default value.");
return output;
}
var bf = new BinaryFormatter();
using (var fs = File.Open(pathString + "/" + name + type, FileMode.Open))
{
output = (T)bf.Deserialize(fs);
}
Debug.Log("[SaveSystem]: Object succesful deserialized!");
return output;
}
}
and use it like
ex = ex.Load("asd", ".dat", SaveExtension.Path.PersistentDataPath);
This way the this T obj is only used to define the type T
Just a hint: You should never use Debug.Log inside of Update ... for debugging simply switch the Inspector in Unity to the Debug mode than you can directly see private fields.

Related

android display arraylist items in dialog

I am having an arraylist fetching name and status of a person. Arraylist is storing the status and name. Its displaying one name at a time. How can I be able to display multiple names at once in alert dialog?
private ArrayList getunfiledRogspDoctorList() {
SqlDataStore sd = new SqlDataStore(this);
sd.open();
String gspQuery = " SELECT * FROM "+ TABLE_DOCTOR + " WHERE " + Queryclass.DOCTOR_ROGSP_STATUS + " == " + 0 + " AND " + Queryclass.DOCTOR_DATE_ID + " = '" + selectionID + "'";
Cursor gspCu = sd.getData(gspQuery);
if(gspCu.moveToFirst()){
do {
rogspname = gspCu.getString(gspCu.getColumnIndex(Queryclass.DOCTOR_CONTACTNAME));
unfiledrogspDoctorList.add(gspCu.getString(gspCu.getColumnIndex(Queryclass.DOCTOR_ROGSP_STATUS)) + rogspname);
}while (gspCu.moveToNext());
}
gspCu.close();
sd.close();
System.out.println("unfiledrogspDoctorList "+unfiledrogspDoctorList);
return unfiledrogspDoctorList;
}
From the code, you are having an ArrayList of your target display String in unfiledrogspDoctorList:
// Suggest to also define the type of your returning ArrayList
private ArrayList<String> getunfiledRogspDoctorList() {
// Define a local ArrayList
ArrayList<String> unfiledrogspDoctorList = new ArrayList<>();
SqlDataStore sd = new SqlDataStore(this);
sd.open();
String gspQuery = " SELECT * FROM "+ TABLE_DOCTOR + " WHERE " + Queryclass.DOCTOR_ROGSP_STATUS + " == " + 0 + " AND " + Queryclass.DOCTOR_DATE_ID + " = '" + selectionID + "'";
Cursor gspCu = sd.getData(gspQuery);
if(gspCu.moveToFirst()){
do {
rogspname = gspCu.getString(gspCu.getColumnIndex(Queryclass.DOCTOR_CONTACTNAME));
unfiledrogspDoctorList.add(gspCu.getString(gspCu.getColumnIndex(Queryclass.DOCTOR_ROGSP_STATUS)) + rogspname);
}while (gspCu.moveToNext());
}
gspCu.close();
sd.close();
System.out.println("unfiledrogspDoctorList "+unfiledrogspDoctorList);
return unfiledrogspDoctorList;
}
You can consider to convert your ArrayList of String into just a String.
private String concat(ArrayList<String> unfiledrogspDoctorList) {
StringBuilder sb = new StringBuilder();
for (String item : unfiledrogspDoctorList) {
sb.append(item);
sb.append(","); // Or change into other separate you would like to display
}
sb.setLength(Math.max(0, sb.length() - 1)); // Remove the appending character
return sb.toString();
}
Then you can make use of an AlertDialog to display that concatenated String.
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder
.setMessage(concat(getunfiledRogspDoctorList()))
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Do anything upon pressing OK button
}
);
AlertDialog alert = builder.create();
alert.show();
You could use :-
SELECT group_concat(name) FROM ....
or to place each on a line you could change the default comma separator to a line feed using
SELECT group_concat(name,'\n') FROM ....
.... representing the rest of the SQL in the question
See https://www.sqlite.org/lang_aggfunc.html#group_concat
note that the GROUP as no GROUP BY clause is provided is a single group (and therefore output row) made up of ALL extracted rows.

Exception: (Index -1 requested, with a size of 2) while retrieving data from a Cursor

Hey I have a problem with accessing the data from a Cursor in Android Studio.
I have two tables in the database events and messages. So each event in the events table may have multiple messages in the messages table. The event and its messages share a common event_id.
I am using LoaderCallbacks to get a Cursor from a ContentProvider. In the ContentProvider query method, I am using a rawQuery to INNER JOIN these two tables.
In this example I query for an event which shares its event_id with two messages from the message table. In the ContentProvider the rawQuery() method with the INNER JOIN was performed.
At this state I can see in the Debugger that the variable mCount from the Cursor is -1. I am not sure what this means but anyways, back in the onLoadFinish() method the Cursor now contains a variable mCursor and this variable again contains a variable mCount which is 2. Which makes sense, since the query should return a Cursor with two rows and since there are two messages. But now I try to get a String with the getString() method and the CursorIndexOutOfBoundsException: Index -1 requested, with a size of 2 is thrown.
I realy don't understand what this means. And I don't find any hint in die Cursor docs, what it means when mCount is -1.
Furthermore in the onLoadFinished method the variable mEditTable is null. And in other queries where I don't join anything it always contains a table.
I am quite sure that the issue somwhere lays with the INNER JOIN, since everything works fine if I use just a query method inside the ContentProvider.query method. But I don't know what I should do differently. I hope you might help me with this. I am aware that, if there is no message related to an event, this query will return an empty cursor with mCount = 0 and then again an exception will be thrown. But this is not the case in this example.
EventProvider class:
public class EventProvider extends ContentProvider {
private static final String LOG_TAG = EventProvider.class.getSimpleName();
private static final int EVENTS = 100;
private static final int EVENT_ID = 101;
private static final int EVENT_MESSAGE_ID = 102;
private static UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private EventDbHelper mEventDbHelper;
static {
sUriMatcher.addURI(EventContract.CONTENT_AUTHORITY, EventContract.PATH_EVENTS, EVENTS);
sUriMatcher.addURI(EventContract.CONTENT_AUTHORITY, EventContract.PATH_EVENTS + "/#", EVENT_ID);
sUriMatcher.addURI(EventContract.CONTENT_AUTHORITY, EventContract.PATH_EVENT_AND_ITS_MESSAGES + "/#", EVENT_MESSAGE_ID);
}
#Override
public boolean onCreate() {
mEventDbHelper = new EventDbHelper(getContext());
return true;
}
#Nullable
#Override
public Cursor query(#NonNull Uri uri, #Nullable String[] projection, #Nullable String selection, #Nullable String[] selectionArgs, #Nullable String sortOrder) {
SQLiteDatabase database = mEventDbHelper.getReadableDatabase();
Cursor retCursor;
final int match = sUriMatcher.match(uri);
switch (match) {
case EVENTS:
retCursor = database.query(EventEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
break;
case EVENT_ID:
selection = EventEntry.COLUMN_EVENT_ID + "=?";
selectionArgs = new String[] {String.valueOf(ContentUris.parseId(uri))};
retCursor = database.query(EventEntry.TABLE_NAME, projection,selection, selectionArgs, null, null, sortOrder);
break;
case EVENT_MESSAGE_ID:
selection = MessageEntry.TABLE_NAME + "." + MessageEntry.COLUMN_EVENT_ID + "=?";
selectionArgs = new String[] {String.valueOf(ContentUris.parseId(uri))};
StringBuilder sqlQuery = new StringBuilder();
sqlQuery.append("SELECT ");
if(projection != null && projection.length > 0) {
for(String s: projection) {
sqlQuery.append(s).append(", ");
}
}
sqlQuery.replace(sqlQuery.length()-2, sqlQuery.length(), " FROM ").append(MessageEntry.TABLE_NAME);
sqlQuery.append(" INNER JOIN ").append(EventEntry.TABLE_NAME).append(" ON ");
sqlQuery.append(EventEntry.TABLE_NAME).append(".").append(EventEntry.COLUMN_EVENT_ID).append("=");
sqlQuery.append(MessageEntry.TABLE_NAME).append(".").append(MessageEntry.COLUMN_EVENT_ID);
sqlQuery.append(" WHERE ").append(selection).append(" ORDER BY ").append(sortOrder).append(";");
Log.v(LOG_TAG, "SQL command for: " + uri.toString());
Log.v(LOG_TAG, sqlQuery.toString());
retCursor = database.rawQuery(sqlQuery.toString(), selectionArgs);
break;
default:
throw new IllegalArgumentException("Cannot query unknown URI: " + uri);
}
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
return retCursor;
}
EventActivity:
#NonNull
#Override
public Loader<Cursor> onCreateLoader(int id, #Nullable Bundle args) {
String[] projection = {
MessageEntry.TABLE_NAME + "." + MessageEntry.COLUMN_EVENT_ID,
MessageEntry.TABLE_NAME + "." + MessageEntry.COLUMN_SENDER,
MessageEntry.TABLE_NAME + "." + MessageEntry.COLUMN_DATE,
MessageEntry.TABLE_NAME + "." + MessageEntry.COLUMN_MESSAGE,
EventEntry.TABLE_NAME + "." + EventEntry._ID,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_NAME,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_DATE,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_DATE_ADDENDUM,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_CONTACT,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_STATUS,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_PICTURE_NAME,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_DESCRIPTION,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_STREET,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_HOUSE_NUMBER,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_POST_CODE,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_CITY,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_EMAIL,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_LOCATION,
EventEntry.TABLE_NAME + "." + EventEntry.COLUMN_SIGNED_UP
};
String sortOrder = MessageEntry.COLUMN_DATE + " DESC";
return new CursorLoader(this, mCurrentEventUri, projection, null, null, sortOrder);
}
#Override
public void onLoadFinished(#NonNull Loader<Cursor> loader, Cursor cursor) {
int indexName = cursor.getColumnIndex(EventEntry.COLUMN_NAME);
int indexImage = cursor.getColumnIndex(EventEntry.COLUMN_PICTURE_NAME);
String imageName = cursor.getString(indexImage); //Here the Exception is thrown
mEventName.setText(cursor.getString(indexName));
mEventAdapter.swapCursor(cursor);
}
If you need something else, I will upload it.
Thanks.
CursorIndexOutOfBoundsException: Index -1 requested, with a size of 2
-1 with Cursors will generally be 1 of 2 issues :-
that the column name passed to getColumnIndex is not a name of a column in the output.
that the Cursor is at the beginning that is at the position that is "before the first row", as is the case when a Cursor is returned.
I suspect that your issue is due to 2 as I believe the message indicates the row of the column.
2 can happen if a move???? (e.g. moveToFirst, moveToNext) method was not actioned (I cannot see any such move in your code) or that the result was not checked (the move methods return true or false to indicate whether or not the move request could be satisfied).
see (probably moveToFirst)
https://developer.android.com/reference/android/database/Cursor#move(int)
https://developer.android.com/reference/android/database/Cursor#moveToFirst()
https://developer.android.com/reference/android/database/Cursor#moveToLast()
https://developer.android.com/reference/android/database/Cursor#moveToNext()
https://developer.android.com/reference/android/database/Cursor#moveToPosition(int)
https://developer.android.com/reference/android/database/Cursor#moveToPrevious()
The fix would be to move the Cursor to a row, checking if the move was actually successful and to then extract the data.
e.g.
String imageName = "No Image"
if (cursor.moveToFirst() && indexImage > -1) {
imageName = cursor.getString(indexImage); //Here the Exception is thrown
}
The above, && indexImage > -1, would also weed out the situation where the column name does not exist in the Cursor.

How do I save Xml Changes Back to the Original Document

I need to update the Styles (styles.xml) part of an MS Word document due to a problem with a vendor's product.
So far I've been able to extract and update the xml I need. The only problem, is that I don't know how to save my changes back to the document.
The code below is working just fine. I usually output the xml to the console to make sure it's going in just fine. At the end, I know I need to perform some save operation, but the XDocument.Save( /stream/) hasn't worked.
Here's where I am so far
static void FixNormal()
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(_path, true))
{
// Get the Styles part for this document.
StyleDefinitionsPart stylesPart = doc.MainDocumentPart.StyleDefinitionsPart;
// If the Styles part does not exist, add it and then add the style.
if (stylesPart == null)
{
Console.WriteLine("No Style Part");
}
else
{
XDocument stylesDoc;
using (var reader = XmlNodeReader.Create(stylesPart.GetStream(FileMode.Open, FileAccess.Read)))
{
XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
Console.WriteLine(stylesPart.Styles.OuterXml);
// Create the XDocument.
stylesDoc = XDocument.Load(reader);
var xStyle = stylesDoc.Descendants(w + "styles").Descendants(w + "style").Where(x => x.Attribute(w + "styleId").Value.Equals("Normal"));
XElement style = xStyle.Single();
var q = style.Descendants(w + "qFormat").FirstOrDefault();
if (q is null)
{
XElement qFormat = new XElement(w + "qFormat");
style.Add(qFormat);
}
var r = style.Descendants(w + "rsid").FirstOrDefault();
if (r is null)
{
XElement rsid = new XElement(w + "rsid");
XAttribute val = new XAttribute(w + "val", "003C4F1E");
rsid.Add(val);
style.Add(rsid);
}
}
//doc.Save(); --- Did not work
}
}
}
I found the answer in the SAVE THE PARTS section of this page Replace the styles parts in a word processing document (Open XML SDK)
See the end of this code for the solution. You'll also see what I've tried.
static void FixNormal()
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(_path, true))
{
// Get the Styles part for this document.
StyleDefinitionsPart stylesPart = doc.MainDocumentPart.StyleDefinitionsPart;
// If the Styles part does not exist, add it and then add the style.
if (stylesPart == null)
{
Console.WriteLine("No Style Part");
}
else
{
XDocument stylesDoc;
using (var reader = XmlNodeReader.Create(stylesPart.GetStream(FileMode.Open, FileAccess.Read)))
{
XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
// Create the XDocument.
stylesDoc = XDocument.Load(reader);
var xStyle = stylesDoc.Descendants(w + "styles").Descendants(w + "style").Where(x => x.Attribute(w + "styleId").Value.Equals("Normal"));
XElement style = xStyle.Single();
var q = style.Descendants(w + "qFormat").FirstOrDefault();
if (q is null)
{
XElement qFormat = new XElement(w + "qFormat");
style.Add(qFormat);
}
var r = style.Descendants(w + "rsid").FirstOrDefault();
if (r is null)
{
XElement rsid = new XElement(w + "rsid");
XAttribute val = new XAttribute(w + "val", "003C4F1E");
rsid.Add(val);
style.Add(rsid);
}
}
//doc.Save(); --- Did not work
//stylesDoc.Save(#"C:\WinTest\HooRah.xml"); -- I only use this to verify that I've updated everything correctly
//using (XmlWriter xw = XmlWriter.Create(stylesPart.GetStream(FileMode.Create, FileAccess.Write)))
//{
// stylesDoc.Save(xw); -- DID NOT WORK EITHER
// doc.Save();
//}
// THIS WORKED
stylesDoc.Save(new StreamWriter(stylesPart.GetStream(FileMode.Create, FileAccess.Write)));
}
}
}

Titan Key with given name does not exist

I create two indexes but when I want to invoke vertex.setProperties(), my program prompts with "given name does not exist.". Below is my code:
initDB
public void tstInitHBase() {
Configuration conf = new BaseConfiguration();
conf.setProperty("storage.backend", "hbase");
conf.setProperty("storage.hostname", "192.168.22.209");
conf.setProperty("storage.port", "2181");
conf.setProperty("storage.tablename", "social_map");
conf.setProperty("cache.db-cache", "true");
conf.setProperty("cache.db-cache-clean-wait", "20");
conf.setProperty("cache.db-cache-time", "180000");
conf.setProperty("cache.db-cache-size", "0.5");
GraphDatabaseConfiguration graphconfig = new GraphDatabaseConfiguration(conf);
try {
graphconfig.getBackend().clearStorage();
} catch (StorageException e) {
e.printStackTrace();
throw new RuntimeException("Techvalley:ERROR 清空数据库失败");
}
TitanGraph graph = TitanFactory.open(conf);
graph.makeKey("PKID").dataType(String.class).indexed(Vertex.class).unique(UniquenessConsistency.LOCK).make();
graph.makeKey("CN_NAME").dataType(String.class).indexed(Vertex.class).make();
graph.makeKey("EDGE_PEERS_WEIGHT").dataType(Long.class).indexed(Edge.class).make();
graph.commit();
}
Insert Data with pig
//objList structure is like (uuid,cn_name,gender,..)
vertex = tx.getVertex(DataType.toString(objList.get(0)));
if (vertex == null) {
logger.info("create node");
vertex = tx.addVertex(DataType.toString(objList.get(0)));
vertex.setProperty(flied[0], DataType.toString(objList.get(0)));
}
/**
*
* */
for (int i = 1; i < flied.length; i++) {
switch (DataType.findType(objList.get(i))) {
case DataType.NULL:
logger.info("cache" + flied[i] + " " + DataType.toString(objList.get(i)));
ElementHelper.setProperties(vertex, flied[i],DataType.toString(objList.get(i)));
break;
case DataType.CHARARRAY:
logger.info("cache" + flied[i] + " " + DataType.toString( objList.get(i)));
ElementHelper.setProperties(vertex, flied[i],DataType.toString(objList.get(i)));
break;
default:
break;
}
}
When I execute ElementHelper.setProperties(vertex,flied[i],DataType.toString(objList.get(i))); my program always returns 'Key with given name does not exist'.
Any ideas?
Find out the offending property key by wrapping ElementHelper.setProperties in try/catch and logging/printing the property key name. Then add it to the graph.makeKey set.

Write files from multiple rest requests

I have a rest service written to receive a file and save it.
The problem is that when I receive more than 2 requests, the files are not written only the last request is taken into consideration and written.
Here is my code:
#POST
#RequestMapping(value = "/media/{mediaName}/{mediaType}")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
#ResponseBody
public String updateResourceLocally(#FormDataParam("rawData") InputStream rawData, #PathVariable("mediaName") String mediaName, #PathVariable("mediaType") String mediaType) {
logger.info("Entering updateResourceLocally for " + jobId + "; for media type: " + mediaType);
final String storeDir = "/tmp/test/" + mediaName + ("/");
final String finalExtension = mediaType;
final InputStream finalRawData = rawData;
// new Thread(new Runnable() {
// public void run() {
// writeToFile(finalRawData, storeDir, finalExtension);
// }
// }).start();
writeToFile(finalRawData, storeDir, finalExtension);
// int poolSize = 100;
// ExecutorService executor = Executors.newFixedThreadPool(poolSize);
// executor.execute(new Runnable() {
// #Override
// public void run() {
// writeToFile(rawData, storeDir, finalExtension);
// }
// });
logger.info("File uploaded to : " + storeDir);
return "Success 200";
}
I tried to put the writeToFile into threads, but still no success. Here is what writeToFile does
public synchronized void writeToFile(InputStream rawData,
String uploadedFileLocation, String extension) {
StringBuilder finalFileName = null;
String currentIncrement = "";
String fileName = "raw";
try {
File file = new File(uploadedFileLocation);
if (!file.exists()) {
file.mkdirs();
}
while (true) {
finalFileName = new StringBuilder(fileName);
if (!currentIncrement.equals("")) {
finalFileName.append("_").append(currentIncrement).append(extension);
}
File f = new File(uploadedFileLocation + finalFileName);
if (f.exists()) {
if (currentIncrement.equals("")) {
currentIncrement = "1";
} else {
currentIncrement = (Integer.parseInt(currentIncrement) + 1) + "";
}
} else {
break;
}
}
int read = 0;
byte[] bytes = new byte[1024];
OutputStream out = new FileOutputStream(new File(uploadedFileLocation + finalFileName));
while ((read = rawData.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
}
The writeToFile creates a folder and writes a file, if the file already exists, it appends 1 and then increments the 1 accordingly and writes the file, so I would get raw.zip, raw-1.zip, etc.
I think the inputstream bytes are being lost, am I correct in my assumption?
NOTE: I do not have a UI client, I am using Poster a Firefox extension.
Update: What I am trying to achieve here is very simple
I receive number of requests with files attached
I need to save them. If the mediaName and mediaType are the same, then I need to append something to the filename and save it in the same location
If they are different I do not have a problem
The problem I am facing with the current code is that, when I post multiple time to the same URL, I have file-names created according to what I want, but the file content is not right, they vary depending on when the request came in and only the last POST's request is written properly.
Eg. I have a zip file of size 250MB, when I post 5 time, the 1st four will have random sizes and the 5th will have the complete 250MB, but the previous four should also have the same content.
You must separate the stream copy from the free filename assignation. The stream copy must be done within the calling thread (jersey service). Only the file naming operation must be common to all threads/requests.
Here is your code with a little refactoring :
getNextFilename
This file naming operation must be synchronized to guarantee each call gives a free name. This functions creates an empty file to guarantee the next call to work, because the function relies on file.exists().
public synchronized File getNextFilename(String uploadedFileLocation, String extension)
throws IOException
{
// This function MUST be synchronized to guarantee unicity of files names
// Synchronized functions must be the shortest possible to avoid threads waiting each other.
// No long job such as copying streams here !
String fileName = "raw";
//Create directories (if not already existing)
File dir = new File(uploadedFileLocation);
if (!dir.exists())
dir.mkdirs();
//Search for next free filename (raw.<extension>, else raw_<increment>.<extension>)
int currentIncrement = 0;
String finalFileName = fileName + "." + extension;
File f = new File(uploadedFileLocation + finalFileName);
while (f.exists())
{
currentIncrement++;
finalFileName = fileName + "_" + currentIncrement + "." + extension;
f = new File(uploadedFileLocation + finalFileName);
}
//Creates the file with size 0 in order to physically reserve the file "raw_<n>.extension",
//so the next call to getNextFilename will find it (f.exists) and will return "raw_<n+1>.extension"
f.createNewFile();
//The file exists, let the caller fill it...
return f;
}
writeToFile
Must not be synchronized !
public void writeToFile(InputStream rawData, String uploadedFileLocation, String extension)
throws IOException
{
//(1) Gets next available filename (creates the file with 0 size)
File file = getNextFilename(uploadedFileLocation, extension);
//(2) Copies data from inputStream to file
int read = 0;
byte[] bytes = new byte[1024];
OutputStream out = new FileOutputStream(file);
while ((read = rawData.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
}