Some MacOSX applications like iTunes don't really have problems when I move a file around - they still find the moved file easily (and I'm pretty sure they have not have opened the file before).
How are they doing it? One possibility I could think of is the FS event notification system. (related question)
But I remember that I have seen some absolute file handle / id or so and I thought that maybe they can always query the current file name by that file handle. Is there something like that? Maybe the inode nr but that is a bit too less because I'm not sure how to get the filename from an inode nr and how to open the file.
As Albert mentioned Alias Manager has been depreciated, the replacement is the URL Bookmark methods
I think what you're looking for is NSURL's bookmarks — I'm on an iPad do unable to produce proper links due to Apple's shortsighted web page design but the essence of it is that you obtain a bookmark from a URL and can subsequently resolve a bookmark back to a URL. The system works around any movements in the file in the interim.
I just found out about the Alias Manager which sounds like what I am searching for. Unfortunately, that seems deprecated. (related question) Some info about the deprecation.
(Another related question) There is also the NSURL class which provides such functions.
Python code:
import AppKit
def getFileNativeId(filepath):
if not os.path.isfile(filepath): return None
filepath = os.path.abspath(filepath)
filepath = unicode(filepath)
url = AppKit.NSURL.alloc().initFileURLWithPath_(filepath)
bookmark = url.bookmarkDataWithOptions_includingResourceValuesForKeys_relativeToURL_error_(AppKit.NSURLBookmarkCreationPreferFileIDResolution,None,None,None)
bytes = bookmark[0].bytes().tobytes()
return bytes
def getPathByNativeId(fileid):
nsdata = AppKit.NSData.alloc().initWithBytes_length_(fileid, len(fileid))
url, _, _ = AppKit.NSURL.URLByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(nsdata, AppKit.NSURLBookmarkResolutionWithoutUI, None,None,None)
if not url: return None
return unicode(url.path())
Related
I see that this has been answered previously by Ken T., but I have a case where the code appears to work, and the call to setxattr() returns 0, but the item I want to modify does not change.
Specifically, I'm trying to change the metadata attribute kMDItemDisplayName, and my call looks like this (modeled after the sample posted by Ken T):
[Note: the "name" param below is an NSString *]
rc = setxattr([pathString cStringUsingEncoding:NSUTF8StringEncoding],
"kMDItemDisplayName",
[name cStringUsingEncoding:NSUTF8StringEncoding],
[name lengthOfBytesUsingEncoding:NSUTF8StringEncoding],
0,
0);
Doing an mdls on the file in question shows that the kMDItemDisplayName attribute is present, but I can't get it to change to anything other than the actual file name (which I assume is the default behavior).
Am I misunderstanding something about how setxattr() is supposed to work?
Any help very much appreciated.
Oh, BTW, why am I trying to do this? It appears (from examining how Bare Bones' Yojimbo does things) that Spotlight uses the kMDItemDisplayName value to list files in the Spotlight search results menu in the finder, which is something I'd like to implement in my app.
Thanks!
Heyyyy... wait a minute...
From the command line, doing xattr -l shows that as far as xattr knows, there is an attribute called kMDItemDisplayName, and it is what I set it to be... However, mdls on the same file still shows the kMDItemDisplayName attribute as the file name.
Do I need to be asking about Launch Services instead of xattr stuff??
OK. After hunting around a bit more and reading more Apple documentation I realized what I need to do. I'm answering my own question in the hope that this information may be of some assistance to someone else down the line.
Because I had to write my own mdimporter to support my app's file format, I thought I'd try adding the kMDItemDisplay name item to the metadata store at metadata import time.
To my amazement and delight, it worked on the first try!
So, the answer is, if you want to overwrite or add custom kMDItem* types, you do so at metadata import time, using a Spotlight importer.
Hope that someone finds this helpful!
I need to use the writeToFile: methods in writing data (that is encrypted) to a file. However, say I have:
NSData *encryptedData = [data AES256EncryptWithKey:key];
And I write the encryptedData to a file by:
[encryptedData writeToFile:#"file.txt" automatically:YES];
This for some reason does not write the data to "file.txt." This is a very simple question and I know I am missing something super basic. If file.txt is not actually there, it must be created.
This probably has nothing to do with Cocoa or NSData.
On Unix (like Mac OS X), paths that start with / are absolute. Paths that start with ~ are relative to the current user's home directory. Anything else (such as file.txt) is relative to the current directory. When running something from Xcode, that is the path of the executable (the compiler's output path).
So, to write that to the desktop, that would be:
[encryptedData writeToFile:#"~/Desktop/file.txt" atomically:YES];
For the documents folder, that would be:
[encryptedData writeToFile:#"~/Documents/file.txt" atomically:YES];
Don't forget that paths are also case-sensitive.
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag
returns a boolean to say if it was successful or not. I'd start there, if you see a YES then the file wrote somewhere successfully.
If that doesn't work then i'd double check the object you're trying to encode supports the NSCoding protocol. If you object doesn't support NSCoding take a look at this blog post for a nifty simple way of adding it.
Also its "atomically" not "automatically" :)
I open a file in windows word and get a handle to the window. Can I get the absolute path of the file (the actual .doc file, not the winword.exe)?
Thanks a lot
You certainly won't be able to do this direct from the Windows API (where a program's document is stored and how it is manageded is not controlled / constrained by the Windows API)...
What you might be able to do is use the Word libraries to iterate through open documents and look for the document with a matching handle, but I doubt this will be simple - I'm not even sure if it will be possible...
Martin.
If I have a string that resolves to a file path in Windows, is there an accepted way to get a canonical form of the file name?
For example, I'd like to know whether
C:\stuff\things\etc\misc\whatever.txt
and
C:\stuff\things\etc\misc\other\..\whatever.txt
actually point to the same file or not, and store the canonical form of the path in my application.
Note that simple string comparisons won't work, nor will any RegEx magic. Remember that we have things like NTFS reparse points to deal with since Windows 2000 and the new Libraries structure in Windows 7.
Short answer: not really.
There is no simple way to get the canonical name of a file on Windows. Local files can be available via reparse points, via SUBST. Do you want to deal with NTFS junctions? Windows shortcuts? What about \\?\-escaped filenames
Remote files can be available via mapped drive letter or via UNC. Is that the UNC to the origin server? Are you using DFS? Is the server using reparse points, etc.? Is the server available by more than one name? What about the IP address? Does it have more than one IP address?
So, if you're looking for something like the inode number on Windows, it ain't there. See, for example, this page.
Roger is correct, there is no simple way. If the volume supports file a unique file index, you can open the file and call GetFileInformationByHandle, but this will not work on all volumes.
The Windows API call GetFullPathName may be the best simple approach.
GetFinalPathNameByHandle appears to do what your asking for, which is available starting with Windows Vista.
Using FileInfo (example in C#):
FileInfo info1 = new FileInfo(#"C:\stuff\things\etc\misc\whatever.txt");
FileInfo info2 = new FileInfo(#"C:\stuff\things\etc\misc\other\..\whatever.txt");
if (info1.FullName.Equals(info2.FullName)) {
Console.WriteLine("yep, they're equal");
}
Console.WriteLine(info1.FullName);
Console.WriteLine(info2.FullName);
Output is:
yep, they're equal
C:\stuff\things\etc\misc\whatever.txt
C:\stuff\things\etc\misc\whatever.txt
jheddings has a nice answer, but since you didn't indicate which language you are using, I thought I'd give a Python way to do it that also works from the command line, using os.path.abspath:
> python -c "import os.path; print os.path.abspath('C:\stuff\things\etc\misc\other\..\whatever.txt')"
C:\stuff\things\etc\misc\whatever.txt
I would use System.IO.Path.GetFullPath. It takes a string as an input (C:\stuff\things\etc\misc\other..\whatever.txt in your case) and will output a string (C:\stuff\things\etc\misc\whatever.txt).
I guess I'm a little late, but you can use System.IO.Path.GetFullPath("C:\stuff\things\etc\misc\other..\whatever.txt") and it will return "C:\stuff\things\etc\misc\whatever.txt"
To get canonical path you should use PathCanonicalize function.
I have a collection of movies and TV shows in iTunes, and I'd like to rename them to an XBMC compatible naming convention without breaking the links in iTunes.
All the necessary metadata (season number, show name, episode number, etc) seems to be in an XML file that iTunes manages, and the episode name is the current file name. So programmatically renaming the files seems fairly straightforward but how do I keep the iTunes library straight at the same time? Is it enough to rewrite the XML file to point to the new file names?
I'd rather not get into applescript if I can avoid it (life is too short), however if it is easier to do it that way I may look at it. Otherwise I'd ideally like to do this in ruby.
On Windows Apple provides the iTunes COM for Windows SDK that works quite well. It is created using a COM interface so it works with almost every language available for Windows. It provides methods for renaming Tracks and Playlists. I have used this to do all kinds of things with my Library.
I do not know what's available on a MAC, but I believe AppleScript is the best native way to access what's available. There is a project called "EyeTunes" that provides a Cocoa framework. There is a site devoted to Applescript ("Doug's AppleScripts for iTunes"). Here is a site showing how to access iTunes from perl.
If you want to rename both the file and the iTunes name then it's probably better to change the track name, remove the file from the library, rename the file, and then re-add the track. You would need to preserve information like last played, playcount, etc.
Not sure if you're on a Windows box but honestly if you can write even a little Javascript the iTunes COM API is very easy to use.
Below is a sample of what it will look like. (this is NOT tested, so only use it as a reference.)
var ITTrackKindFile = 1;
var iTunesApp = WScript.CreateObject("iTunes.Application");
var deletedTracks = 0;
var mainLibrary = iTunesApp.LibraryPlaylist;
var tracks = mainLibrary.Tracks;
var numTracks = tracks.Count;
var i;
var RenameTarget;
while (i > 0)
{
var currTrack = tracks.Item(numTracks);
// is this a file track?
if (currTrack.Kind == ITTrackKindFile)
{
RenameTarget = "Stuff from other properties"
currTrack.Name = RenameTarget; //
}
numTracks++;
}
Good Luck.
Late but I needed exactly the same for Plex on OS X.
My solution was to write a Python script that queries iTunes for its TV shows via the AppleScript bridge, gets the file path from each track's location attribute and then creates a symlink to the original file, using iTunes metadata to give the link a name suitable for Plex/XBMC etc.
The advantage is you can painlessly create multiple sets of links with different naming schemes, e.g. My Name Is Earl S01E10.m4v or My Name Is Earl 01x10 White Lie Christmas.m4v
The core of the script is (where track is the reference provided by the appscript bridge):
def trackInfo(track):
"""returns tuple (filename, filepath, show)
track is iTunes playlist track from appscript bridge,
filename is of format "Showname 01x02 Episode Name.avi" where
01 is the season number, 02 the episode number and the extension
will match that of filepath.
filepath is the UNIX path to the original file.
"""
try:
path = track.location().path
except CommandError:
return None, None, None
ext = os.path.splitext(path)[1]
name = "%s %02dx%02d %s%s" % (track.show(), track.season_number(),
track.episode_number(), track.name(), ext)
return name, path, track.show()
I use identify2 for mac to rename my shows - works great!
Check out EpNamer at http://www.epnamer.com/. It requires .NET but is exactly what you're looking for and XBMC is exactly what I use it for too.
You might also look into using Media Companion since you're most likely using the library functionality of XBMC, which you can read about here:
http://xbmc.org/forum/showthread.php?p=217769
It'll make .nfo and .tbn files for each movie and TV show that you've got which XBMC will scrape before going out to the internet for information.
Enjoy!
Another way to play with the iTunes xml file is to use the plist module.