📄 filehandler.java
字号:
* Initialize a <tt>FileHandler</tt> to write to a set of files * with optional append. When (approximately) the given limit has * been written to one file, another file will be opened. The * output will cycle through a set of count files. * <p> * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt> * properties (or their default values) except that the given pattern * argument is used as the filename pattern, the file limit is * set to the limit argument, and the file count is set to the * given count argument, and the append mode is set to the given * <tt>append</tt> argument. * <p> * The count must be at least 1. * * @param pattern the pattern for naming the output file * @param limit the maximum number of bytes to write to any one file * @param count the number of files to use * @param append specifies append mode * @exception IOException if there are IO problems opening the files. * @exception SecurityException if a security manager exists and if * the caller does not have <tt>LoggingPermission("control")</tt>. * @exception IllegalArgumentException if limit < 0, or count < 1. * */ public FileHandler(String pattern, int limit, int count, boolean append) throws IOException, SecurityException { if (limit < 0 || count < 1) { throw new IllegalArgumentException(); } checkAccess(); configure(); this.pattern = pattern; this.limit = limit; this.count = count; this.append = append; openFiles(); } // Private method to open the set of output files, based on the // configured instance variables. private void openFiles() throws IOException { LogManager manager = LogManager.getLogManager(); manager.checkAccess(); if (count < 1) { throw new IllegalArgumentException("file count = " + count); } if (limit < 0) { limit = 0; } // We register our own ErrorManager during initialization // so we can record exceptions. InitializationErrorManager em = new InitializationErrorManager(); setErrorManager(em); // Create a lock file. This grants us exclusive access // to our set of output files, as long as we are alive. int unique = -1; for (;;) { unique++; if (unique > MAX_LOCKS) { throw new IOException("Couldn't get lock for " + pattern); } // Generate a lock file name from the "unique" int. lockFileName = generate(pattern, 0, unique).toString() + ".lck"; // Now try to lock that filename. // Because some systems (e.g. Solaris) can only do file locks // between processes (and not within a process), we first check // if we ourself already have the file locked. synchronized(locks) { if (locks.get(lockFileName) != null) { // We already own this lock, for a different FileHandler // object. Try again. continue; } FileChannel fc; try { lockStream = new FileOutputStream(lockFileName); fc = lockStream.getChannel(); } catch (IOException ix) { // We got an IOException while trying to open the file. // Try the next file. continue; } try { FileLock fl = fc.tryLock(); if (fl == null) { // We failed to get the lock. Try next file. continue; } // We got the lock OK. } catch (IOException ix) { // We got an IOException while trying to get the lock. // This normally indicates that locking is not supported // on the target directory. We have to proceed without // getting a lock. Drop through. } // We got the lock. Remember it. locks.put(lockFileName, lockFileName); break; } } files = new File[count]; for (int i = 0; i < count; i++) { files[i] = generate(pattern, i, unique); } // Create the initial log file. if (append) { open(files[0], true); } else { rotate(); } // Did we detect any exceptions during initialization? Exception ex = em.lastException; if (ex != null) { if (ex instanceof IOException) { throw (IOException) ex; } else if (ex instanceof SecurityException) { throw (SecurityException) ex; } else { throw new IOException("Exception: " + ex); } } // Install the normal default ErrorManager. setErrorManager(new ErrorManager()); } // Generate a filename from a pattern. private File generate(String pattern, int generation, int unique) throws IOException { File file = null; String word = ""; int ix = 0; boolean sawg = false; boolean sawu = false; while (ix < pattern.length()) { char ch = pattern.charAt(ix); ix++; char ch2 = 0; if (ix < pattern.length()) { ch2 = Character.toLowerCase(pattern.charAt(ix)); } if (ch == '/') { if (file == null) { file = new File(word); } else { file = new File(file, word); } word = ""; continue; } else if (ch == '%') { if (ch2 == 't') { String tmpDir = System.getProperty("java.io.tmpdir"); if (tmpDir == null) { tmpDir = System.getProperty("user.home"); } file = new File(tmpDir); ix++; word = ""; continue; } else if (ch2 == 'h') { file = new File(System.getProperty("user.home")); if (isSetUID()) { // Ok, we are in a set UID program. For safety's sake // we disallow attempts to open files relative to %h. throw new IOException("can't use %h in set UID program"); } ix++; word = ""; continue; } else if (ch2 == 'g') { word = word + generation; sawg = true; ix++; continue; } else if (ch2 == 'u') { word = word + unique; sawu = true; ix++; continue; } else if (ch2 == '%') { word = word + "%"; ix++; continue; } } word = word + ch; } if (count > 1 && !sawg) { word = word + "." + generation; } if (unique > 0 && !sawu) { word = word + "." + unique; } if (word.length() > 0) { if (file == null) { file = new File(word); } else { file = new File(file, word); } } return file; } // Rotate the set of output files private synchronized void rotate() { Level oldLevel = getLevel(); setLevel(Level.OFF); super.close(); for (int i = count-2; i >= 0; i--) { File f1 = files[i]; File f2 = files[i+1]; if (f1.exists()) { if (f2.exists()) { f2.delete(); } f1.renameTo(f2); } } try { open(files[0], false); } catch (IOException ix) { // We don't want to throw an exception here, but we // report the exception to any registered ErrorManager. reportError(null, ix, ErrorManager.OPEN_FAILURE); } setLevel(oldLevel); } /** * Format and publish a <tt>LogRecord</tt>. * * @param record description of the log event */ public synchronized void publish(LogRecord record) { if (!isLoggable(record)) { return; } super.publish(record); flush(); if (limit > 0 && meter.written >= limit) { // We performed access checks in the "init" method to make sure // we are only initialized from trusted code. So we assume // it is OK to write the target files, even if we are // currently being called from untrusted code. // So it is safe to raise privilege here. AccessController.doPrivileged(new PrivilegedAction() { public Object run() { rotate(); return null; } }); } } /** * Close all the files. * * @exception SecurityException if a security manager exists and if * the caller does not have <tt>LoggingPermission("control")</tt>. */ public synchronized void close() throws SecurityException { super.close(); // Unlock any lock file. if (lockFileName == null) { return; } try { // Closing the lock file's FileOutputStream will close // the underlying channel and free any locks. lockStream.close(); } catch (Exception ex) { // Problems closing the stream. Punt. } synchronized(locks) { locks.remove(lockFileName); } lockFileName = null; lockStream = null; } private static class InitializationErrorManager extends ErrorManager { Exception lastException; public void error(String msg, Exception ex, int code) { lastException = ex; } } // Private native method to check if we are in a set UID program. private static native boolean isSetUID();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -