retrieving and writing a file in iOS - ios

I looked at many SO question where the user wanted to access a document in his app directory. I am new to all of this and just want some clarification on the matter. I am building an open-source content blocker for iOS 9.
You can see the file tree. I wonder if it is possible to access the file called blockerList.json which is in the folder Adblock Content Blocker. My goal was to write the json file based on what the user want to build. I need to be able to modify the content of this file. Is this possible or should I stop trying and leave it like that?
Thanks for any help.

The app bundle is readonly as #dan said. So you have to copy the file from bundle into the Document directory then you able to modify the file at anytime.
Copy file into document like this:
class func copyFile(fileName: String) {
let destPath: String = getPathInDocument(fileName)
var fromPath = NSBundle.mainBundle().pathForResource("blockerList", ofType: "json")!
var fileManager = NSFileManager.defaultManager()
if !fileManager.fileExistsAtPath(destPath) {
fileManager.copyItemAtPath(fromPath, toPath: destPath, error: nil)
} else {
println("The file allready exists at path:\(destPath)")
}
}
class func getPathInDocument(fileName: String) -> String {
return NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0].stringByAppendingPathComponent(fileName)
}
Hope this will help you!

Note : You have readonly permission for application's bundle file.
Firstly copy file in NSDocumentDirectory with backup attribute. Use refrerence copy file to document directory iphone and for How do I prevent files from being backed up to iCloud and iTunes?
Check references ImportingJSONFile and Y6JSONFileManager-iOS to read and write changes in JSON File.

Related

is the temporaryDirectory of FileManager automatically removed by iOS? if so when?

I am adding an option in my App to backup everything to a file.
For that, I am serializing all my objects to a dictionary that I save in a single file in the path provided by FileManager.default.temporaryDirectory. Then I ask the user for a path to save this file using a UIDocumentPickerViewController.
Everything works fine, but I wonder what happens with the temporal file that I created in the temporaryDirectory. Is this automatically removed by the operating system? should I take care of removing it by myself?
This is how I get the path of the temporary directory for my file:
private var exportURL: URL {
let documentURL = FileManager.default.temporaryDirectory
let fileName = "archive"
let filePath = "\(fileName).backup"
return documentURL.appendingPathComponent(filePath)
}

iOS writing compressed NSData to a file generates corrupted zip file

I'm trying to achieve a very simple thing in my iOS app: zip a file in Documents folder. I wrote the following FileManager extension:
extension FileManager {
func zipFile(url: URL, deleteOriginal: Bool = false) {
guard let fileData = try? Data(contentsOf: url) else { return }
let nsdata = fileData as NSData
let zipped: NSData
zipped = (try? nsdata.compressed(using: .zlib)) ?? nsdata
let zip = zipped as Data
let zipUrl = url.deletingPathExtension().appendingPathExtension("zip")
try? FileManager.default.removeItem(at: zipUrl)
try? zip.write(to: zipUrl)
if deleteOriginal {
try? FileManager.default.removeItem(at: url)
}
}
}
However, the created file seems to be is corrupted.
I go to Xcode -> Window -> Devices and Simulators, select my device, then my app in the list below it, click the gear button under the list and then click on Download Container... to see the files. Then I open the contents of the downloaded package and check the Documents folder - it has the created zip file in it. However, I cannot open it. By default Mac creates a file with zip.cpgz extension which it usually does when the file is corrupted. Other extractor apps show an error message telling the file is corrupted. When I try to open it in the terminal using unzip I see the following message:
iMac:Downloads user$ unzip myzip.zip
Archive: myzip.zip
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
unzip: cannot find zipfile directory in one of myzip.zip or
myzip.zip.zip, and cannot find myzip.zip.ZIP, period.
I tried not only NSData.compressed, but also a library called DataCompression, and also implemented compression "myself" using Apple instructions from here. In all of the cases the file was corrupted the same way.
I also tried to debug my code, displayed the compressed Data object in debugger and export it as a file. Again corrupted with the same symptoms.
Is there something that I'm doing wrong? Please let me know how to compress and save stuff to a file, not just [NS]Data, like in most of the answers in StackOverflow.
ZIP is an archive file format which also supports compression (but it can also contain uncompressed files).
A ZIP archive contains more than just the compressed file contents. It also maintains an index of all files, directories & symlinks. This index is called Central Directory and it is appended to the end of the file. Additionally each file in the archive also gets some metadata attached. This local file header carries information such as file creation date, file attributes, file paths, ...
You can find a full specification of the ZIP format here.
I published a small framework that can be used to work with ZIP archives in Swift: https://github.com/weichsel/ZIPFoundation
Using this framework, you can create an archive from a single file by using the following code:
let fileManager = FileManager()
let currentWorkingPath = fileManager.currentDirectoryPath
var sourceURL = URL(fileURLWithPath: currentWorkingPath)
sourceURL.appendPathComponent("file.txt")
var destinationURL = URL(fileURLWithPath: currentWorkingPath)
destinationURL.appendPathComponent("archive.zip")
do {
try fileManager.zipItem(at: sourceURL, to: destinationURL)
} catch {
print("Creation of ZIP archive failed with error:\(error)")
}

iOS reading from a file

I'm trying to get my iPhone app to load text from a file into a string array, with 1 line from the file per array element.
I've created an input file as a text file using sublime text. I dragged the file (which is located inside of a folder inside of my project directory) into xCode into a folder in the same location in the project heirarchy.
I also tried adding it as a bundle (by copying the folder and renaming it with the .bundle extension), to no avail. Currently, my app has the file in 2 places (Obviously I plan to delete the unneeded version, but I'm not sure how this will work so I've left it for now).
I've written a function that I want to read my file, and assemble its contents into an array:
func readFromFile(filename: String) -> [String]? {
guard let theFile = Bundle.main.path( forResource: fileName, ofType: "txt") else {
return nil // ALWAYS returns nil here: Seems 'filename' can't be found?????
}
do { // Extract the file contents, and return them as a split string array
let fileContents = try String(contentsOfFile: theFile)
return fileContents.components(separatedBy: "\n")
} catch _ as NSError {
return nil
}
}
As it stands, the function always returns nil at the location commented in the code.
I've been working on this for ~6hrs (and tried every suggestion I could find on StackOverflow, google etc) and I'm just getting more and more confused by the differences between the various versions of Swift and intricacies of iOS development. I can't seem to find a consistent answer anywhere. I've checked the apple documentation but it's too high level with no example code for me to understand at my swift beginner level.
I also tried naming the file with a ".txt" extension but that didn't help either.
The file must certainly be named alert01.txt if you are going to refer to it as forResource: "alert01", ofType: "txt".
Loading from a bundle will not work. The file needs to be part of your project as shown in the first entry.
However, your code is not going to work because you have created a folder reference. That means the folder PanicAlertFiles is being copied with all its contents into your bundle. Your code will need to dive into that folder in order to retrieve your file. Use path(forResource:ofType:inDirectory:) to do that, or (if you don't want to have to code the file name explicitly) get the folder and then use the FileManager to examine its contents.

Permanent file directory in Xcode

In the documents directory for my app, I have a file Q1.dat which I use in my program. I access it through the path:
func createArrayPath () -> String? {
if let docsPath: String = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).last {
return ((docsPath as NSString).stringByAppendingPathComponent("Q1") as NSString).stringByAppendingPathExtension("dat")
}
return nil
}
When I run the program on a different device however, a different documents directory is created, and the file is no longer present. Is there a place I can put the file so that I can always access it no matter what device I am running on?
The Documents directory is meant for data created by the user.
It sounds like you want to bundle a resource with your application. You can do this by simply dragging the file into Xcode, which will automatically set it up to be copied into your app bundle, and you can find it using URLForResource(_:withExtension:).
If the file is very large, you might want it to be downloaded separately from the main app. For this you can use the new On-Demand Resources feature.

How to input a default .txt file into an iPhone through Xcode in Swift

I am trying to read from a text file that I have already created on my desktop. I put this Story.txt into the corresponding file path on my computer through Xcode, something along these lines :
(/Users/username/Library/Developer/CoreSimulator/Devices/12F046A7-a lot more numbers/data/Containers/Data/Application/8AECCA06-160C-4702-B16E-FF50B2A145F5)
and the code works perfectly. However, when I try to run the app on my iPhone, it changes the file path and Xcode doesn't automatically transfer my files to my iPhone documents folder at this file path.
(/var/mobile/Containers/Data/Application/139C80A3-more numbers/Documents)
How do I manually put a .txt file at this location?
Here is the code I use to read the file.
func loadStory()
{
if let dir : NSString = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true).first
{
let path = dir.stringByAppendingPathComponent("Story.txt")
print(path)
do
{
//reads file
let text:String = try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding) as String
}
catch {/* error handling here */}
}
}
Since it seems you want the file included with your app, do not attempt to manually install the file somewhere on your computer. That only works with the Simulator if you happen to put the file in just the right place.
Instead, add the file to your Xcode project. Then the file will be added to your app's resource bundle. Then you can access the file using NSBundle to get its path. It will not be in the app's Documents folder. It will be in the app's bundle.
See Where to place a .txt file and read from it in a IOS project for more details.
You need to add it to your project. Drag and drop it inside your project so it'll be bundled in. Than you can access it using
Let string = NSBundle.mainBundle().resourcePath as NSString
String.stringByAppendingPathComponent('Story.txt')
If you could change the file from .txt to plist, you could integrate it on your project, and never think where it is, it will be always accessible.

Resources