renebigot / XlsxReaderWriter

XlsxReaderWriter is an Objective-C library for iPhone / iPad and Mac. It parses and writes MS Excel XLSX files.
MIT License
437 stars 121 forks source link

BRAOfficeDocument object is getting data nil while we fetch file from document directory #63

Open puka9x opened 7 years ago

puka9x commented 7 years ago

I'm a having problems when open file form Document directory

NSString *documentPathOff = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"DungDTchecked.xlsx"];

BRAOfficeDocumentPackage *spreadsheet = [BRAOfficeDocumentPackage open:documentPathOff];

Error: Error while loading content of file [Content_Types].xml.

Error Domain=NSCocoaErrorDomain Code=260 "The file “[Content_Types].xml” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/Users/trivm/Library/Developer/CoreSimulator/Devices/5CC7E12F-01AD-4BD8-9D73-78EC185DF228/data/Containers/Data/Application/76E94945-C6FC-4A8A-AA05-152F45AE46F2/Library/Caches/fr.brae.spreadsheetdocument/DungDTchecked.xlsx/[Content_Types].xml, NSUnderlyingError=0x7fa861423940 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}} 2016-12-19 17:16:26.798 MoKet[7996:196880] Error while loading content of file .rels.

Error Domain=NSCocoaErrorDomain Code=260 "The file “.rels” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/Users/trivm/Library/Developer/CoreSimulator/Devices/5CC7E12F-01AD-4BD8-9D73-78EC185DF228/data/Containers/Data/Application/76E94945-C6FC-4A8A-AA05-152F45AE46F2/Library/Caches/fr.brae.spreadsheetdocument/DungDTchecked.xlsx/_rels/.rels, NSUnderlyingError=0x7fa861630f80 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

PLEASE HELP ME.

renebigot commented 7 years ago

Have you create your file with Excel ? It looks like it's a bad formatted file you're trying to open

Treverr commented 7 years ago

I am getting the same thing, I tested with a brand new XLSX file and I still get the same error

charlymr commented 7 years ago

A bit late to the party, but there is an issue that can be easily fix:

https://github.com/renebigot/XlsxReaderWriter/pull/52/commits/a09fcd6152ff9bfeec97ff1526427af900365f8b

See PR #52

jNoxx commented 7 years ago

I still have the same issue, even with Charlymr's PR.

macshodan commented 6 years ago

Hi, I'm having a similar problem. I've implemented the UIDocumentPickerViewController to let the user import the file. The picker mode is set to import, and I can successfully import the xlsx file in the application tmp directory. When I pass the url absolute string to BROfficeDocumentPackage open function it returns an error because it's look like it's searching for the file in the Library/Caches of the Application instead of the url I've been giving. The same file added as a resource of the App and opened with the Bundle.main.pathForResource methods works...

charlymr commented 6 years ago

Guys the cache directory is use to access the content of the file. Think of the XLS file as a zip with lot of data and it is extractcting it there!

Are you sure you are giving the right path to the file? It’s weird you get it to work from the main bundle resource and not elsewhere.

macshodan commented 6 years ago

Hi, first of all thanks for your quick reply. I'm posting the code of documentPickerDelegate to see if I'm missing something, as well as the consolle output:

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
        for url in urls {
            debugPrint("Selected document at: \(url.absoluteString)")

            let spreadsheet: BRAOfficeDocumentPackage = BRAOfficeDocumentPackage.open(url.absoluteString)
            if let worksheet: BRAWorksheet = spreadsheet.workbook.worksheets.first as? BRAWorksheet {
                debugPrint("Worksheet has: \(worksheet.rows.count) rows and each row has: \(worksheet.columns.count) columns")
            }
        }
    }

Here's the log from the console:

"Selected document at: file:///private/var/mobile/Containers/Data/Application/B4D79AF5-64C0-4AF1-A65E-450A3FA8F50A/tmp/com.codeland.C-Track-Inbox/INVENTARIO_P&G_311217.xlsx"
2018-01-11 14:56:31.002112+0100 C-Track[5614:2521838] Error while loading content of file [Content_Types].xml.

Error Domain=NSCocoaErrorDomain Code=260 "Impossibile aprire il file “[Content_Types].xml” perché non c'è un file di quel tipo." UserInfo={NSFilePath=/var/mobile/Containers/Data/Application/B4D79AF5-64C0-4AF1-A65E-450A3FA8F50A/Library/Caches/fr.brae.spreadsheetdocument/INVENTARIO_P&G_311217.xlsx/[Content_Types].xml, NSUnderlyingError=0x1c4459620 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
2018-01-11 14:56:31.003645+0100 C-Track[5614:2521838] Error while loading content of file .rels.

Error Domain=NSCocoaErrorDomain Code=260 "Impossibile aprire il file “.rels” perché non c'è un file di quel tipo." UserInfo={NSFilePath=/var/mobile/Containers/Data/Application/B4D79AF5-64C0-4AF1-A65E-450A3FA8F50A/Library/Caches/fr.brae.spreadsheetdocument/INVENTARIO_P&G_311217.xlsx/_rels/.rels, NSUnderlyingError=0x1c044b100 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

Thanks in advance for your help.

charlymr commented 6 years ago

I think the problem is that you file is not accessible as it is outside your Sandbox. This why it works when you put the file in the Main Bundle

Try this way and let me know:

        for url in urls {
            debugPrint("Selected document at: \(url.absoluteString)")

            url. startAccessingSecurityScopedResource()

            let spreadsheet: BRAOfficeDocumentPackage = BRAOfficeDocumentPackage.open(url.absoluteString)
            if let worksheet: BRAWorksheet = spreadsheet.workbook.worksheets.first as? BRAWorksheet {
                debugPrint("Worksheet has: \(worksheet.rows.count) rows and each row has: \(worksheet.columns.count) columns")
            }
        }

    }

Check this: Apple-startaccessingsecurityscopedreso

Be careful not to let the file open. (This is why I would suggest copying the file to your sandbox before opening it and delete it later if you perform only read).

macshodan commented 6 years ago

Thanks again for your quick response. Unfortunately that wasn't the culprit. I've instantiated the documentPickerViewController in .import mode, and when I startAccessingSecurityScopedResource() it returns false (as per Apple means that the resource was accessible). I've also tried to copy the file to another location and then used that, still getting the same error, here's the new code:

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {

        let newUrls = urls.flatMap { (url: URL) -> URL? in

            debugPrint("Document Picker received url: \(url)")

            let access = url.startAccessingSecurityScopedResource()

            // Create file URL to temporary folder
            var tempURL = URL(fileURLWithPath: NSTemporaryDirectory())
            // Apend filename (name+extension) to URL
            tempURL.appendPathComponent(url.lastPathComponent)
            do {
                if FileManager.default.fileExists(atPath: tempURL.path) {
                    try FileManager.default.removeItem(atPath: tempURL.path)
                }
                // Copy file from app_id-Inbox to tmp/filename
                try FileManager.default.copyItem(atPath: url.path, toPath: tempURL.path)
                if access {
                    url.stopAccessingSecurityScopedResource()
                }
                return tempURL
            } catch {
                if access {
                    url.stopAccessingSecurityScopedResource()
                }
                print(error.localizedDescription)
                return nil
            }
        }

        for url in newUrls {
            let access = url.startAccessingSecurityScopedResource()
            debugPrint("Moved document url: \(url.absoluteString)")
            if let spreadsheet: BRAOfficeDocumentPackage = BRAOfficeDocumentPackage.open(url.absoluteString) {
                if let worksheet: BRAWorksheet = spreadsheet.workbook.worksheets.first as? BRAWorksheet {
                    debugPrint("Worksheet has: \(worksheet.rows.count) rows and each row has: \(worksheet.columns.count) columns")
                }
            }
            if access {
                url.stopAccessingSecurityScopedResource()
            }
        }
    }

Of course the output is the same... thanks again for bothering you.

charlymr commented 6 years ago

Arf...

Ok my best guess then is to check it in the simulator and see of the app container react (if the file copied, etc...) If the cache is open when you open the file...

Another thing, are you using Cocoapods? If so, which version. I did some changes on my fork and I am using it in my apps with no issue with very large files Xcode 9.2 Swift 4. If you want to give it a try and let me know how it react https://github.com/charlymr/XlsxReaderWriter/commits/master

macshodan commented 6 years ago

Thanks! No, I'm not using cocoa pods, I've downloaded the project from GitHub and added as submodulte to my project. I'm going to try yours and let you know.

thanks.

macshodan commented 6 years ago

Hi, it's me again, sorry.

I'm trying to get your fork, but I'm unable to add it, either as a submodule either with cocoa pods. I've followed your suggestion, added the source at the PodFile, but when I link your repository and trying to pod install I have the following error: [!] Unable to find a specification for SSZipArchive (~> 1.1) depended upon by XlsxReaderWriter

I've tried to run pod install on your cloned project and it works...

charlymr commented 6 years ago

Normally it should work out of the box. https://github.com/renebigot/XlsxReaderWriter/issues/88

Add this at the top of your PodFile source 'https://github.com/charlymr/XlsxReaderWriter-Podspecs.git'

Then you can get the latest version 2.3.2

     pod 'XlsxReaderWriter', '~> 2.3.2'
macshodan commented 6 years ago

yeah, that's exactly what I did... :(

charlymr commented 6 years ago

Are you using SSZipArchive elsewhere?

Try :

pod setup # If not done already
pod repo update
macshodan commented 6 years ago

No I'm not.... I've tried added it as specific pod and it works. I'm trying the setup and repo update. I'll keep you posted. Thanks

macshodan commented 6 years ago

nothing changed... :(

charlymr commented 6 years ago

Weird. You have use_frameworks! in your pod?

macshodan commented 6 years ago

yes I have... should I try to remove it?

charlymr commented 6 years ago

Nope. Keep it.

macshodan commented 6 years ago

I've tried to remove it but it didn't work :)

charlymr commented 6 years ago

Well I am not sure now :( where to take it. You said when you open the sample project it works. Try and implement the document picker there and see if the problem come from the Excel file maybe?

charlymr commented 6 years ago

Just checked in the project I am working right now this is what get install:

Using SSZipArchive (1.8.1)
Using XMLDictionary (1.4.1)
Using XlsxReaderWriter (2.3.2)
macshodan commented 6 years ago

Yeah I should try that... the problem is if it works I still need to find a way to use it in my project.

Trying that now, thanks!

macshodan commented 6 years ago

Am I missing something in the pod file?

# Uncomment the next line to define a global platform for your project
platform :ios, '10.3'
source 'https://github.com/charlymr/XlsxReaderWriter-Podspecs.git'

target 'C-Track' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for C-Track
  pod 'XlsxReaderWriter', '~> 2.3.2'
end
charlymr commented 6 years ago

But if it works, you will have some clue on where the problem might come from!

It's always 10% of time coding, 90% debugging ! That's how it works :)

charlymr commented 6 years ago

I don't see anything missing

charlymr commented 6 years ago

Wait... Add this:

source 'https://github.com/CocoaPods/Specs'
source 'https://github.com/charlymr/XlsxReaderWriter-Podspecs.git' 
charlymr commented 6 years ago

The master repo it might be the problem!

macshodan commented 6 years ago

YESSS! It worked! Thanks a lot really!

charlymr commented 6 years ago

So you are sorted and the file open?

macshodan commented 6 years ago

No... right now I've managed to get the library installed with cocoa pods... now I'm trying to open the file. I'll keep you posted. Thanks again.

macshodan commented 6 years ago

Hi.... unfortunately it's not working either. Same error as the old library. Just a curiosity, how are you using it in your project? How do you get the excel files on the device?

charlymr commented 6 years ago

This work for me:

 public func importDocument(at url: URL) {

        if url.startAccessingSecurityScopedResource()  {

            let alert = UIAlertController(title: "Data Update", message: "Do you want to update the XLS data with that one? \(url.lastPathComponent)", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Cancel", style: .cancel,  handler: { (_) in
                url.stopAccessingSecurityScopedResource()
            }))
            alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (_) in

                do {
                    try XLSData.main._refreshData(template: url, resetData: true)

                } catch let error as XLSImportError {

                    let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
                    self.present(alert, animated: true, completion: nil)

                } catch { }
                url.stopAccessingSecurityScopedResource()

            }))
            present(alert, animated: true, completion: nil)
        }

    }

where XLSData is a wrapper implementing this... It essentially copy the file locally from what I am calling the Template (as for modification I want the original to be intact and I found that the copy file from the lib is poorly implemented.

    func _refreshData(template: URL, resetData: Bool? = false, skipMain: Bool? = false) throws {

        if resetData == true {
            docName = template.lastPathComponent
        }

        let filePathURL          =  documentDirectoryURL.appendingPathComponent(docName)

        // For our subclass
        guard shouldAttempToRefreshIndicatorWith(filePath: filePathURL, template: template, resetFile: resetData ?? false) == true else {
            return
        }
        _extractInProgress = true

        if resetData == true, FileManager.default.fileExists(atPath: filePathURL.path) {
            if _details?.isOpened() ?? false {
                _details?.close()
            }
            try! FileManager.default.removeItem(at: filePathURL)
        }

        // For our subclass
        willAttempToRefreshIndicator(filePath: filePathURL, template: template, resetFile: resetData ?? false)

        var details: XLSTemplateFile {
            if let current = _details,
                current.filepath     == filePathURL.path,
                current.templatepath == template.path,
                current.isOpened() {
                return current

            } else if let current = _details {
                current.close()
            }

            _details = XLSTemplateFile(filepath: filePathURL.path, templatepath: template.path)
            guard let details = _details else {
                fatalError()
            }
            return details
        }

        print("Path: " + filePathURL.path)

        if let workBook = details.excelSheet.workbook {
            if skipMain == false {
                self.units = try details.getMainData(for: workBook)
            }
            if _extractProfiles {
                self.profiles = try details.getProfilesData(for: workBook)
            }
        }

        // For our subclass
        didRefreshIndicator(data: self.units)

        _extractInProgress = false

    }
macshodan commented 6 years ago

Thanks I'm going to look at it. Thanks again for all your help! Have a nice evening.

UtkarshDuPont commented 5 years ago

Hi, try once adding below code under Document Picker Delegate: didPickDocumentsAt

var filePath = url.absoluteString filePath = filePath.replacingOccurrences(of: "file:/", with: "") let spreadsheet: BRAOfficeDocumentPackage = BRAOfficeDocumentPackage.open(filePath)