the below shown functions are working well in Xcode, as long as I use them in OSX-applications...
now I wrote an iOS-application where I would like to save some data in .txt files and read them again, but it does not work... there are neither files written, nor read...
I already searched the net for solutions but I only found solutions to whenever it does not work in the OSX application (wrong directory, etc...) but that is not my case, there I already got it working...
what is the difference when I use it in the iOS simulator and how to get it running there?
//the below code is now the corrected version (before it was posted without the "this was missing" part.
void SaveData(std::string FileName)
{
//!!this was missing
char *H = getenv("HOME");
std::string Home(H);
std::string FileName = Home + "/Documents/" + FileName;
std::ofstream FileOut (FileName);
if (FileOut.is_open())
{
//!!write data to file
FileOut.close();
}
}
void LoadData(std::string FileName)
{
//!!this was missing
char *H = getenv("HOME");
std::string Home(H);
std::string FileName = Home + "/Documents/" + FileName;
std::ifstream FileIn;
FileIn.open(FileName.c_str(), std::ios::in);
if(not FileIn.good())
{
//!!error message
return;
}
//!!read data from file
FileIn.close();
}
iOS is Sandboxed and restricts the area that can be read and written to and users/me/documents/xcodeprojects is incorrect.
See About the iOS File System for details.
There are several directories you can write and the Documents directory is probably what you want. You have to make a call to get the path, here are example calls in C++, Objective-C and Swift:
C++ (Thx: Moritz Buchty):
char *H = getenv("HOME");
std::string Home(H);
std::string FileName = Home + "/Documents/" + FileName;
ObjC:
NSArray *documentDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
Swift:
let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as! String
You need to save the file to your application's Documents folder. For more information about it, read this answer.
Related
I have my files saved on resources folder and when I try to write other thing it does not work. Could anyone help me?
public void SaveGameData()
{
PlayerSavedData aux = new PlayerSavedData();
aux.allSavedPlayerData = SavePlayerInformation.playerDataList.ToArray<PlayerData> ();
string dataAsJson = JsonUtility.ToJson (aux);
string filePath = Application.persistentDataPath + "playerInformation.json";
File.WriteAllText (filePath, dataAsJson);
}
This is wrong
string filePath = Application.persistentDataPath + "playerInformation.json";
Try this instead
string filePath = Path.Combine(Application.persistentDataPath,"playerInformation.json");
Also note that you need WRITE_EXTERNAL_STORAGE permission
The Resoures folder simply doens't exist any more afer your build. The assets in the Resources folder get packed into the game's archive for assets.
Better you put file in StreamingAssets folder.
I have the following problem: I extracted a zip file via SSZipArchive (in a Swift app) and there are some file names with "invalid" characters.
I think the reason is that I zipped the files under Windows and so the names are now coded in ANSI.
Is there a way to convert all the "corrupted" folder and file names during the unzip process?
Or later? It would be no problem if I have to iterate over the folder tree and rename the files.
But I have no idea how to find out which names are set in ANSI and I also don't know how to correct the charset.
The official spec says that the path should be either encoded in Code Page 437 MS-DOS Latin US or UTF-8 (if Bit 11 of the general purpose field is set):
D.1 The ZIP format has historically supported only the original IBM PC
character encoding set, commonly referred to as IBM Code Page 437.
This limits storing file name characters to only those within the
original MS-DOS range of values and does not properly support file
names in other character encodings, or languages. To address this
limitation, this specification will support the following change.
D.2 If general purpose bit 11 is unset, the file name and comment
should conform to the original ZIP character encoding. If general
purpose bit 11 is set, the filename and comment must support The
Unicode Standard, Version 4.1.0 or greater using the character
encoding form defined by the UTF-8 storage specification. The
Unicode Standard is published by the The Unicode Consortium
(www.unicode.org). UTF-8 encoded data stored within ZIP files is
expected to not include a byte order mark (BOM).
I recently released a Swift open source implementation of the ZIP file format called ZIPFoundation. It conforms to the standard and should be able to detect Windows path names and decode them properly.
Probably fixed in latest SSZipArchive (currently 2.1.1). I've implemented support for non-Unicode filenames in a way similar to the code below, so you can reuse it to process your filenames yourself if you want.
OK, it's in Objective-C, but as SSZipArchive has the fix in itself already, you shouldn't need it anymore. Otherwise, either make a bridging header to include the objective-c code to your swift app, or convert it to Swift (should be easy).
#implementation NSString (SSZipArchive)
+ (NSString *)filenameStringWithCString:(const char *)filename size:(uint16_t)size_filename
{
// unicode conversion attempt
NSString *strPath = #(filename);
if (strPath) {
return strPath;
}
// if filename is non-unicode, detect and transform Encoding
NSData *data = [NSData dataWithBytes:(const void *)filename length:sizeof(unsigned char) * size_filename];
// supported encodings are in [NSString availableStringEncodings]
[NSString stringEncodingForData:data encodingOptions:nil convertedString:&strPath usedLossyConversion:nil];
if (strPath) {
return strPath;
}
// if filename encoding is non-detected, we default to something based on data
// note: hexString is more readable than base64RFC4648 for debugging unknown encodings
strPath = [data hexString];
return strPath;
}
#end
#implementation NSData (SSZipArchive)
// initWithBytesNoCopy from NSProgrammer, Jan 25 '12: https://stackoverflow.com/a/9009321/1033581
// hexChars from Peter, Aug 19 '14: https://stackoverflow.com/a/25378464/1033581
// not implemented as too lengthy: a potential mapping improvement from Moose, Nov 3 '15: https://stackoverflow.com/a/33501154/1033581
- (NSString *)hexString
{
const char *hexChars = "0123456789ABCDEF";
NSUInteger length = self.length;
const unsigned char *bytes = self.bytes;
char *chars = malloc(length * 2);
// TODO: check for NULL
char *s = chars;
NSUInteger i = length;
while (i--) {
*s++ = hexChars[*bytes >> 4];
*s++ = hexChars[*bytes & 0xF];
bytes++;
}
NSString *str = [[NSString alloc] initWithBytesNoCopy:chars
length:length * 2
encoding:NSASCIIStringEncoding
freeWhenDone:YES];
return str;
}
#end
I am trying to find the parser in Caffe. By parser, I mean the part of the code that reads the network configuration from a file and parses it. I was wondering if anyone knows where in the Caffe codebase I should look for this specific piece of code.
Caffe's text file format for specifying models uses the Google Protocol Buffer format.
You can see the code that reads a model in src/caffe/util/io.cpp:
bool ReadProtoFromTextFile(const char* filename, Message* proto) {
int fd = open(filename, O_RDONLY);
CHECK_NE(fd, -1) << "File not found: " << filename;
FileInputStream* input = new FileInputStream(fd);
bool success = google::protobuf::TextFormat::Parse(input, proto);
delete input;
close(fd);
return success;
}
Try using GitHub's search to see places in the code that call this function.
I have built a Server that you can upload files to and download, using Eclipse, servlet and jsp, it's all very new to me. (more info).
Currently the upload system works with the file's name. I want to programmatically assign each file a random key. And with that key the user can download the file. That means saving the data in a config file or something like : test.txt(file) fdjrke432(filekey). And when the user inputs the filekey the servlet will pass the file for download.
I have tried using a random string generator and renameTo(), for this. But it doesn't work the first time, only when I upload the same file again does it work. And this system is flawed, the user will receive the file "fdjrke432" instead of test.txt, their content is the same but you can see the problem.
Any thoughts, suggestions or solutions for my problem?
Well Sebek, I'm glad you asked!! This is quite an interesting one, there is no MAGIC way to do this. The answer is indeed to rename the file you uploaded. But I suggest adding the random string before the name of the file; like : fdjrke432test.txt.
Try this:
filekey= RenameRandom();
File renamedUploadFile = new File(uploadFolder + File.separator+ filekey+ fileName);
item.write(renamedUploadFile);
//remember to give the user the filekey
with
public String RenameRandom()
{
final int LENGTH = 8;
StringBuffer sb = new StringBuffer();
for (int x = 0; x < LENGTH; x++)
{
sb.append((char)((int)(Math.random()*26)+97));
}
System.out.println(sb.toString());
return sb.toString();
}
To delete or download the file from the server you will need to locate it, the user will input the key, you just need to search the upload folder for a file that begins with that key:
filekey= request.getParameter("filekey");
File f = new File(getServletContext().getRealPath("") + File.separator+"data");
File[] matchingFiles = f.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith(filekey);
}
});
String newfilename = matchingFiles[0].getName();
// now delete or download newfilename
I am doing iPhone app dev. Usually, I put image(photo) files and some other configuration files in to supporting folder.
Can I update those files in supporting folder from server? If can, how to do it?
If not, can I pre-store the files which are need to upload into Document Folder and download newer files in document folder to replace older files?
we had the same problem in our current app. our final approach is this:
1) the assets we want to deliver with the app are stored inside a folder under Resources.
2) Plus there is an XML file telling us, which asset belongs where and how old it is (timestamp).
3) When the app starts for the first time, we copy all files (except the xml) from Rescources to the app's Cache folder:
// get the app's cache folder
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
_cachesDirectory = [paths objectAtIndex:0];
_assetDirectory = [NSString stringWithFormat:#"%#/assets", _cachesDirectory];
// copy everything
_fmngr = [NSFileManager defaultManager];
- (void) copyAllFilesFromInitialFolder:(NSString*)path
{
NSArray *files = [_fmngr contentsOfDirectoryAtPath:path error:nil];
for (NSString *file in files)
{
if ([file isEqualToString:[NSString stringWithFormat:#"%#.xml", kDefaultXMLFileName]])
{
continue;
}
NSString *fpath = [NSString stringWithFormat:#"%#/%#", path, file];
BOOL isDir;
if ([_fmngr fileExistsAtPath:fpath isDirectory:&isDir])
{
if (isDir)
{
[self copyAllFilesFromInitialFolder:fpath];
}
else
{
NSString *relPath = [fpath substringFromIndex:[_initialLangDeviceContentPath length]+1];
NSString *fileName = [self convertFilePathToName:relPath];
NSString *tpath = [NSString stringWithFormat:#"%#/%#", _assetDirectory, fileName];
NSError *error;
BOOL success = [_fmngr copyItemAtPath:fpath toPath:tpath error:&error];
if (!success || error)
{
NSLog(#"INFO: copy %# to CACHES failed ... file may already be there.", file);
}
}
}
}
}
4) At the next start of the application, we check online if there are newer files on our update server. The XML from step 2) also resides on the server and has to be updated when JPGs/PNGs/... are updated/replaced on the server.
If nothing changed our PHP script returns a 304 "not modfied" - otherwise it'll output an updated version of the XML.
the PHP script looks something like this:
$doc = new DOMDocument();
#$doc->load($filename);
$xpath = new DOMXPath($doc);
$assets = $xpath->query('//asset');
if ($assets->length > 0)
{
foreach ($assets as $asset)
{
$assetPath = $asset->getAttribute('path');
if (file_exists($assetPath))
{
$atime = filemtime($assetPath);
$asset->setAttribute('modified', $atime);
}
else
{
// file not found - link broken
$asset->setAttribute('modified', '0');
}
}
}
$output = $doc->saveXML();
header('Content-type: text/xml');
echo $output;
The app downloads and parses the generated XML, comparing all modified values.
When there is an asset with a newer modified timestamp it is deleted locally and redownloaded. only after this check is completed the app starts - and you got the new assets on the device.
Hope this helps. We had some problems with the last modified attribute of the files we deliver with the app. When including the files into the app bundle and copying them at runtime, the files last modified is always the time of the first start of the app. sometimes you already updated some files on the server - but because the app thinks the files on the device are newer (because they were copied just now) they are not re-dowloaded from the server :(
so you can't work with the real file's attributes but have to include the actual file-date inside the XML file.