text:
Articles preaching the virtues of writing clean code are abundant with good reason: some things bare repeating. Like any topic covering such an esoteric subject, there are a wide range of opinions as to what exactly defines "clean code". At the end of the day, there are two criterion for clean code:
- Efficiency: Does the code run as quickly and efficiently as possible? Does the code make the most of it's objects and variables with maximum reuse and minimal waste?
- Maintainability: Is the code easy to understand for other developers? Is it well planned, logical, properly documented, and easy to update?
This article will discuss the various elements comprising these two broad points regarding clean code, and provide examples in everyones favorite open source language: PHP. The target audience here is the beginner PHP programmer, although other levels of PHP programmers may find some useful information within.
{mospagebreak title=Loops & Other Conditionals}
One way or another, all pseudo code is eventually converted to machine code. This code will occupy some finite amount of memory. Some languages, such as Java and the .NET Framework go through some extra steps for portability sake before producing machine code by generating IL (Intermediary Language) code. Although it is not always a point of concern, the machine code produced can vary wildly in size based on the pseudo code a developer produces. In PHP, there are a few key ways to minimize the amount of memory and machine code overhead generated by your application. In a small personal site this may not matter, but in a performance-critical situation, the savings here can be just as valuable as the savings earned by writing efficient database queries. The best place to start the discussion is with loops and conditional statements.
Case Statements – A case statement produces roughly 1/5th the amount of machine code as an if/else structure that completes the same task. Use case statements whenever possible! You can use a case statement when you are expecting an object to contain a particular value chosen from a range of known values. Case statements also allow you to provide a default fork for unknown values, which makes it possible to use a case statement in the majority of places where you may want to use an if/else statement. The difference in memory overhead between these two statements is fairly nominal, but the case statement is more efficient to some small degree.
Loops – Loops vary more drastically than conditionals due to the nature of the operations they perform. PHP offers a number of loops, including some higher level looping methods based on the each() function. When deciding what type of loop to use, consider the operations taking place. Let's look at the following example, where we have a query that will return roughly 1,500 results.
$r = mysql_query('SELECT * FROM someTable LIMIT 1500');
for ($i = 0; $i < mysql_num_rows($r); $i++) {
print mysql_result($r, $i, 'ColA').mysql_result($r, $i, 'ColB');
while (($row = mysql_fetch_assoc($r)) !== false) {
print $row['ColA'].$row['ColB'];
The first option requires simply one scalar variable used as a counter for iteration, using a lightweight access method to read buffered data from a result handle. The second example uses an array constructor function to build an array and evaluate it's contents on each iteration, and then references the array two times per iteration. Despite what you may guess, "OPTION 2" runs significantly faster. It has lower memory and machine code overhead. The examples are somewhat poor in that they demonstrate poorly written code; database access handled in-line with iteration, and output mixed in. Ignore that. The building blocks are what contribute to the overall overhead of the application, and understanding that will help you make the right choices for your application. You may find it easier to use an associative array in iterations than a result handle cursor, but in a proper app, you would be performing this operation at the object level, and output would be handled elsewhere, driven by object oriented iteration of the values that were loaded into an object from our query.
{mospagebreak title=Objects}
Objects can cripple your page load time in PHP. PHP is still a young language and with version 5 will finally support "real" Objects, and supposedly offer faster compilation of objects. This is a good thing, as there is little room for a non-object-oriented application in the real world. When you are assembling objects in code, the natural thing to do is to simply copy objects as needed. For example, say every object in your application requires a database object to populate itself and save it's state. However, since PHP is middle-ware and there should never be concurrent database access by a single PHP page, it makes sense to have your objects share a single database object. This point spans a vast array of situations where objects need to be shared and passed around. C++ programmers understand this concept, as C++ has wretched garbage collection. Fortunately, PHP does not share this shortcoming, but poor memory use within an application page can still result in pathetic load times and a crippled server if there are a lot of concurrent users and a lot of objects being copied haphazardly.
The point of this section is this: carefully consider the way in which you utilize objects in your PHP code. It is perfectly fine to have PHP that is completely object oriented and has nothing more than the equivalent of a Main() in a C++ app, but you must consider how your objects will be used, how large the contents of those objects will be, and how they will share those contents and methods.
Best Practices
This section could be made an entire book on it's own, and often has. It is subject to much debate and a variety of standards. As with any language, some best practices can be applied to that language specifically. An example that truly stands out is using single quotes (') vs using double quotes ("). The PHP parser treats these two token identifiers very different. PHP treats anything inside a matching pair of single quotes as a string literal and does not parse the contents of that string. However, PHP treats anything inside a matching pair of double quotes as string data that may contain references to instance variables, objects, or functions, and will parse the contents of the string. This can result in major performance disparities in a page with extensive data output. I ran a quick test printing 1,000 lines of output in the following two methods:
print "The value of variable A is $a. The value of variable B is $b. The value of variable C is $c.
print 'The value of variable A is '.$a.'. The value of variable B is '.$b.'. The value of variable C is '.$c.'.
Option 2 ran roughly thirty percent faster on my server. Results will vary per server and page size. The big difference between these two examples is that in Option 1, PHP is required to full parse the contents of the string, doing printf-style substitution for instance variables. Option 2 is the equivalent of concatenating seven string literal values together and printing them out, which requires no actual string parsing, just some in-memory operations and a call to stdout.
Other "best practices" that are more thoroughly documented include:
- Using a consistent and logical naming convention for objects, functions, classes, etc.
- Commenting code line by line (or as near to line by line as is needed to clearly explain what operations are being performed).
- Indenting code to reflect the beginning and ending of statements (particularly statements enclosed in curly braces).
- Organizing files in a logical directory structure with easy to understand directory and file names.
- Making code as modular and reusable as possible.
These things may seem obvious to seasoned programmers, but for a lot of beginners, these are things that are often overlooked in haste. All of these best-practices contribute to code reusability, readability, and maintainability, which is the topic of the next page.
{mospagebreak title=Code Reusability & Maintainability}
This is arguably the most critical point of the article. So maybe a project was a one-off and you'll never use the code again. Maybe you will never have to go back and add support for another vendors database product. But guess what: someone else will have to. And, in all likelihood, at some time or another in every programmers career, he will be that "someone". Assembly language programmers can easily relate to this, probably more so than any other developer. Code that is difficult or impossible to understand and extend is often referred to as "write-only" code. This is less common in higher level languages but can still exist. "Write-only" means that the code is so convoluted or complex that without proper comments and documentation, it is impossible to modify or extend in any way. That cool algorithm you wrote with one letter variables names and excessive use of by-reference parameter passing may be a great achievement to you as a developer, but six months later when you need to do the same routine + X, and you pull up the old code and realize it's not documented or maintainable, you get to go back to the drawing board. That cool algorithm just became a pain in the neck.
So, come to terms with it now: you need to document your code. Not only do you need to document your code, but you need to follow a lot of other guidelines to make sure your code is as reusable and maintainable as possible (many of which are discussed throughout this article).
We've talked about maintainability, now let's touch on reusability. Routines are often written as band-aids for a change in application design after development. These band-aid routines tend to be hard coded for a particular task and are often far more complex than the application routines that were in place before, because they are solutions applied to a problem that is outside of their scope. That is, they are applied in a situation where a higher level design change was required. These are the most notoriously difficult routines to maintain. Your day to day routines can also be excessively annoying to reuse, because they were written to perform one particular task in one particular way. The key here is abstraction. If you are writing code for one specific problem, try to analyze the problem at the interface level. "How does this routine talk to the application?" It isn't so much about "What does this routine do?", because you can write a routine capable of just about anything. The key to reuse is to find the level of abstraction at which the routine becomes reusable. You must determine the cost of producing a highly reusable routine when you are patching code, because in the real world, we don't always have time to kick back and refactor an application to suit one or two new features that seem small to the end user and the client.
There are a number of things that contribute to the development of "clean code". How clean your code is can be determined by measuring the efficiency and maintainability of the application code you (or your team) has written and assessing the weak areas of the code. The fewer weak areas of code you find, and the simpler the code is to understand and reuse, the better. Code that is obvious in function (through logically organized, well documented routines and application flow) and easy to maintain (through portability and well planned architecture) is clean code. Writing clean code simply requires that you take the time and effort to plan, document, and organize your projects. As you develop more applications, you will notice that planning and development takes less time and you will be able to reuse more and more code for future projects.
I hope this article will be of use to beginning PHP programmers, and that it will help you grow as a developer!


text:
They Not Playin: Lil Boosie's Trial Starts Jury Selection! The Jurors Will Not Be Named, Will Be Staying At Hotels Away From Their Family & Security Will Be Extra Tight
Please click the "Report" button below if the video on this page is not working properly.
Comments will only be displayed by verified emails. No Spamming or Racism.

subset: commoncrawl


text:
Nitz Quick Print Copy Systems
Address:889 R. Papa Street 1008
Phone:+63 (2) 735-0169
Similar Businesses In our Database
We apologize but we do not have other business similar to this listing in our database.
If this is not the business you are looking for, you can also Search our Directory. Please feel free to Contact Us with your comments and/or suggestions.


text:
We're starting off the new month with some enhancements to site, and some good news for web developers. Here's what's happening.
Answers: Search and FAQ
We took the occasion of writing a new Webfont FAQ to polish up our site search tools: you'll find both resources available here. In addition to some guided tours of topics like licensing and troubleshooting, you'll find updated answers to questions about publishing apps, making PDFs, and more. Since the tool searches across the entire site, look for some colorful surprises, in case you just happen to be searching for poodle's paws, lightning bolts, Tupac Shakur, Zipf's Law, or any of the three places we mentioned Steve McQueen, which science can't explain.
Larger Desktop Licenses
We've been delighted to see organizations of every size adopt Cloud.typography, from independent developers subscribing at $99 to high-traffic websites who measure visitors in the billions. In keeping with the range of webfont subscriptions we offer, today we're expanding the range of desktop licenses that can be purchased online: starting today, you can license fonts online for as many as 250 computers. As always, our sales office is happy to assist organizations who need even bigger licenses. Drop us a line.
Webfont Domains
One of Cloud.typography's highlights is that it lets you deliver webfonts to an unlimited number of domains. We've heard from designers who enable a single domain such as example.com that traffic to www.example.com is blocked, because the www hasn't been explicitly included. Starting today, every time you add a domain, the www subdomain is automatically whitelisted, and vice versa: adding www.example.com whitelists example.com as well. If you're grappling with an especially gruesome list of subdomains, you can use the asterisk as a wild card to authorize them all, by adding *.example.com. There's more about this in the Cloud.typography User Guide.
We're hiring!
The best news of all: we're hiring! With Cloud.typography up and running, and the next generation of web applications in the works, it's a great time to join a small and dedicated team of obsessives, and to build things for an audience who appreciates good design. This is a full-time position in our New York office, open to US citizens and others with authorization to work in the US. Tell your friends. —JH


text:
Spy vs. Spy
Bob Clarke was an American illustrator and cartoonist, and a longtime contributor to MAD Magazine. Born Robert J. Clarke in Mamaronceck, New York, he began his career at the age of 17 as a ghost artist on 'Ripley's Believe It Or Not'. He joined the army two years later, and became an artist with the European editions of Stars and Stripes magazine.
Back in civil life, he became a commercial artist with the ad firm Geyer, Newell and Ganger, where he did designs for the Cutty Sark label and the Candyland board game. He became part of the "Usual Gang of Idiots" at MAD Magazine after the departure of editor Harvey Kurtzman. An avid prankster himself, Clarke drew over 600 features for MAD, including the Ripley parody 'Believe It or NUTS!' and several years of 'Spy vs. Spy' stories.
Bob Clarke passed away from complications of pneumonia in his hometown Seaford at age 87 on 31 March 2013.


text:
Dear visitor, welcome to SPRINKLER TALK FORUM - You Got Questions, We've Got Answers. If this is your first visit here, please read the Help. It explains how this page works. You must be registered before you can use all the page's features. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.
Friday, April 13th 2007, 5:33pm
Supreme Member
Location: USA
Saturday, April 14th 2007, 5:53am
Saturday, April 14th 2007, 12:01pm
Saturday, April 14th 2007, 3:35pm
Saturday, April 14th 2007, 4:57pm
Sunday, April 15th 2007, 6:15am
Sunday, April 15th 2007, 11:16am
Sunday, April 15th 2007, 12:06pm
Supreme Member
Monday, April 16th 2007, 5:25am
New Member
Location: USA
Thursday, April 19th 2007, 5:06am


text:
Download wallpaper
Here are 51+ Akuma Wallpaper Hd below for your personal computer or mobile phone. These funny backgroud images are all free to your. Choose hd wallpapers with different resolutions depending on the screen size of your device. To find more Wallpapers for pc, phone or TV? Just to search on this site.


text:
Schools:Kingston Catholic
Delivery: On Call
*All orders for school delivery need to be received by noon the day before scheduled delivery date*
Barcone's Music welcomes you and your young artist to the exciting world of music. Instrumental music provides a positive outlet for self-expression. Participation in a school music program will enrich your child's learning experience through self-discipline and responsibility.
Barcone's is a family run business that has represented quality and integrity for generations. We currently provide services to over 90 school music programs in 8 counties.
We are proud to participate in this worthwhile musical experience with your child.


text:
01 - Heavy Lifting
About 601 Tully
Check out our new website! 601Tully.syr.edu
601 Tully is a center for engaged practice in Syracuse, NY developed by artist and professor Marion Wilson with a rotating collaborative team of 54 students and neighbors and Anda French of French 2Design. It's a site for meaningful exchange between artists, community members, and scholars in the co-production of culture.
601 Tully includes a contemporary art space, a public events space, a bookstore, a teaching garden, and Recess Cafe West.
In 2009, Wilson purchased the condemned two-story home and local drug hub, and throughout five semesters, Wilson's design/build class re-zoned, designed, renovated and now sustains the physical and programmatic aspects of 601 Tully. The collaborative team has consisted of artists, architects, environmentalists, Fowler High School students, Green Train Workforce, neighbors, and the occasional passerby.
601 Tully is made possible by the generous support of the Syracuse University School of Education, The Kauffman Foundation, The Near West Side Initiative, Imagining America, Home HeadQuarters Inc., Say Yes to Education, and National Grid.
Find us on Facebook!
Wednesday, June 30, 2010
Work continues
01 - Heavy Lifting


text:
This is an excerpt from the article by Steven Rosenbaum and published by Forbes.
"It used to be that company communication was all top down.
Today, things are changing fast – as the tools and networks for communication are broken wide open.
Within the world of corporate communication, there are new school of thought that say there are the thinkers who are looking to turn this big noisy mess into value for their brands and corporate parents.
Ben Edwards the VP Digital Strategy and Development for IBM explains: ""I think there are some emerging roles, potential roles for you know, coms professionals to think about. One of them I think a lot about is this notion of curation."
At IBM, the voice of the company is increasingly coming from the intranet, known internally as W3. W3 has been leading a transformation from professional to user-generated content within IBM.
The IBM vision is to embrace, rather than ignore the growing voice and knowledge of their community. "One of the measures that we like to talk about is called 'Professionally Produced Content versus Employee Published Content'.
"We think we have a role in bringing the external perspective into the employee base" says Edwards. That makes IBM a curator as much as a communicator.
Read full article here: http://onforb.es/Igx7tm
Via Giuseppe Mauriello


text:
A cheesesteak is a long, crusty roll filled with thinly sliced sautéed ribeye beef and melted cheese. Generally, the cheese of choice is Cheez Whiz, but American and provolone are common substitutions. The art of cheesesteak preparation lies in the balance of flavors, textures and what is often referred to as the drip factor. Other toppings may include fried onions, sautéed mushrooms, ketchup and hot or sweet peppers. A lot of resto nowadays offers a large variation of cheesesteaks suited to your taste.
Boo's Philly Cheesesteaks and Hoagies
Figueroa Philly Cheese Steak
Big Mike's Philly Steaks and Subs
Boo's Philly Cheesesteaks and Hoagies
Philadelphia Sandwiches
Yummy Philly Cheese Steak
Great Steak
Philly Steak Depot
Quickie's Pizza & Subs
Philly Pizza & Grill
Big Mike's Philly Steaks & Sub
Philadelphia Steak & Hoagie
Hoagies & Wings
Philly's Best
Papa Jakes Sub Shop
Great Steak
California Steak and Fries
Jersey Mike's Subs
Mr V's Philly Cheesesteak & Burritos
Eat Vinnys
Big Mike's Philly Steaks and Subs
Philly West Bar & Grill
Harvey's Sandwich Shop
Philly's Best
Philly's Best
The Bazaar by José Andrés
Bera's Cheese Steaks
Philly's Best
Sam's Philly Steak Depot
Cheesesteaks Plus
Taylor's Steak House
Great Steak
Big Jo's
Hot Wings Cafe
North End Pizzeria
The Great Western Steak & Hoagie Co.
Pizza Man
Nonnos Kitchen
Phil's Deli
McCormick & Schmick's Seafood & Steaks
Green Hut Cafe LLC
Jersey Mike's Subs
Pacific Dining Car
Jersey Mike's Subs
Mastro's Steakhouse
Nick & Stef's Steakhouse
Fonz's Restaurant
Monty's Steakhouse
Fat Sal's Deli
Victor Jr's
Belcampo Meat Co.
Charley's Philly Steaks Delivery
George Petrelli Famous Steakhouse
Outlaws Cafe
Philie B's
Morton's The Steakhouse
The Cheesecake Factory
Omaha Steaks
Cheesesteaks are a civic icon, a tourist draw and a cultural obsession.


text:
Table of Contents:
Chapter One
Sitting on his throne, the Ghost King of World's End looked down on his kneeling Ghosts. Not a single Ghost spoke or moved. The years of living under the Ghost King's strict rule had quite disciplined the Ghosts. They moved or spoke only when the Ghost King ordered them to, not before. And anyone who did speak out of turn . . . well, the Ghost King had specific punishments in store for those who did not respect his authority.
The Ghosts all wore identical pale white armor, which shone dimly in the light of the bluish torches mounted on the walls. They had long monkey-like tails wrapped around their waists, short, sharp claws, and little tri-crowns of horns on their heads.
Their appearance reminded the Ghost King of his own appearance. He, too, was pale white, but even paler than they. Like the Ghosts, he had three horns on his head, but his were longer and sharper than theirs. He was far taller and bulkier than they, too, and his eyes were green as opposed to yellow.
The Ghost King raised his sword and said, "All stand."
The Ghosts rose as one. Each Ghost slammed their fists together in the traditional salute, which created a loud echo in the stone chamber that quickly faded at a gesture from the Ghost King.
"Now, my Ghosts," said the Ghost King, looking over them all dispassionately. "For years, our island of World's End has been ignored by the outside world. Our island has remained nothing more than a legend to outsiders, which is why we have been at peace for so many years."
None of the Ghosts said anything, but the Ghost King, through his telepathy, heard thoughts such as And that has nothing to do with us from one disgruntled Ghost, a sentiment that was shared by the others. That was good. The Ghost King despised arrogance, for it often led to rebellion. By making it clear they were not responsible for this peace, the Ghosts could not become prideful, or so the Ghost King believed.
"Now my Ghosts," the Ghost King continued, "through my supernatural intuition and link to the spirits, I have discovered that four invaders have arrived on this island. What's more, they were sent by my mortal enemy to kill me."
Again, the Ghosts' discipline kept them from reacting. The Ghost King went over their minds again and heard thoughts such as Impossible! from one Ghost and What could this mean? from another, although their bodies betrayed no reactions to the news.
"Allow me to repeat that," the Ghost King said. He held up his left hand and began counting off his fingers. "Not one, nor two, nay, not just three, but four invaders, sent here to kill me. My enemy is too cowardly to show his face to me, but it is no coincidence that these invaders appear on my island at the same time that my enemy's power has risen to unforeseen heights."
The Ghost King again scanned their thoughts and heard one Ghost thinking What can we do against the Ghost King's enemy?, words which described the others' feelings quite well. Nor did the Ghost King see fit to comfort them. Fear was the primary tool with which he controlled the Ghosts. He made sure they were always afraid, so they would never think of overthrowing him.
"Tira, Balon, Virof," said the Ghost King, beckoning toward the three Ghosts standing at the front. "Come here."
The three Ghost Lieutenants walked up to the Ghost King's throne. They stopped at the step just below the Ghost King's feet and kneeled.
The Ghost King looked at his Lieutenants. Tira was thin and had a long scar running down her right cheek. Balon was muscular and had a knife strapped to his chest. Virof was taller than the last two, with longer claws than the others'. Though perhaps not all three Lieutenants were equal in their loyalty to him, the Ghost King did not doubt that they would do whatever he ordered them to do.
"I give you orders to lead the Ghosts to eliminate these invaders," the Ghost King said, tapping each Lieutenant on the shoulder with his sword as he spoke. "Do not return until you can bring me their heads in a bag. They are at Skull Beach."
"We shall not fail you, Your Highness," said Tira.
"Then go!" the Ghost King ordered, pointing at the door with his sword. "Leave and do whatever it takes to save your king!"
The Lieutenants nodded. A second later, all of the Ghosts had teleported out of the room. The Ghost King sat alone on his throne as memories flooded through his mind, memories of his enemy and of a time long ago, when things were not quite as grim as they were today.
My old enemy, the Ghost King thought. You really think you've gotten me this time. You will be surprised.
Edited by TNTOS, Dec 18 2013 - 04:30 PM.


text:
Lipid, any of a diverse group of organic compounds including fats, oils, hormones, and certain components of membranes that are grouped together because they do not interact appreciably with water. One type of lipid, the triglycerides, is sequestered as fat in adipose cells, which serve as the energy-storage depot for organisms and also provide thermal insulation. Some lipids such as steroid hormones serve as chemical messengers between cells, tissues, and organs, and others communicate signals between biochemical systems within a single cell. The membranes of cells and organelles (structures within cells) are microscopically thin structures formed from two layers of phospholipid molecules. Membranes function to separate individual cells from their environments and to compartmentalize the cell interior into structures that carry out special functions. So important is this compartmentalizing function that membranes, and the lipids that form them, must have been essential to the origin of life itself.
Water is the biological milieu—the substance that makes life possible—and almost all the molecular components of living cells, whether they be found in animals, plants, or microorganisms, are soluble in water. Molecules such as proteins, nucleic acids, and carbohydrates have an affinity for water and are called hydrophilic ("water-loving"). Lipids, however, are hydrophobic ("water-fearing"). Some lipids are amphipathic—part of their structure is hydrophilic and another part, usually a larger section, is hydrophobic. Amphipathic lipids exhibit a unique behaviour in water: they spontaneously form ordered molecular aggregates, with their hydrophilic ends on the outside, in contact with the water, and their hydrophobic parts on the inside, shielded from the water. This property is key to their role as the fundamental components of cellular and organelle membranes.
Although biological lipids are not large macromolecular polymers (e.g., proteins, nucleic acids, and polysaccharides), many are formed by the chemical linking of several small constituent molecules. Many of these molecular building blocks are similar, or homologous, in structure. The homologies allow lipids to be classified into a few major groups: fatty acids, fatty acid derivatives, cholesterol and its derivatives, and lipoproteins. This article covers the major groups and explains how these molecules function as energy-storage molecules, chemical messengers, and structural components of cells.
Fatty acids
Fatty acids rarely occur as free molecules in nature but are usually found as components of many complex lipid molecules such as fats (energy-storage compounds) and phospholipids (the primary lipid components of cellular membranes). This section describes the structure and physical and chemical properties of fatty acids. It also explains how living organisms obtain fatty acids, both from their diets and through metabolic breakdown of stored fats.
Biological fatty acids, members of the class of compounds known as carboxylic acids, are composed of a hydrocarbon chain with one terminal carboxyl group (COOH). The fragment of a carboxylic acid not including the hydroxyl (OH) group is called an acyl group. Under physiological conditions in water, this acidic group usually has lost a hydrogen ion (H+) to form a negatively charged carboxylate group (COO−). Most biological fatty acids contain an even number of carbon atoms because the biosynthetic pathway common to all organisms involves chemically linking two-carbon units together (although relatively small amounts of odd-number fatty acids do occur in some organisms). Although the molecule as a whole is water-insoluble by virtue of its hydrophobic hydrocarbon chain, the negatively charged carboxylate is hydrophilic. This common form for biological lipids—one that contains well-separated hydrophobic and hydrophilic parts—is called amphipathic.
In addition to straight-chain hydrocarbons, fatty acids may also contain pairs of carbons linked by one or more double bonds, methyl branches, or a three-carbon cyclopropane ring near the centre of the carbon chain.
Saturated fatty acids
The simplest fatty acids are unbranched, linear chains of CH2 groups linked by carbon-carbon single bonds with one terminal carboxylic acid group. The term saturated indicates that the maximum possible number of hydrogen atoms are bonded to each carbon in the molecule. Many saturated fatty acids have a trivial or common name as well as a chemically descriptive systematic name. The systematic names are based on numbering the carbon atoms, beginning with the acidic carbon. The table gives the names and typical biological sources of the most common saturated fatty acids. Although the chains are usually between 12 and 24 carbons long, several shorter-chain fatty acids are biochemically important. For instance, butyric acid (C4) and caproic acid (C6) are lipids found in milk. Palm kernel oil, an important dietary source of fat in certain areas of the world, is rich in fatty acids that contain 8 and 10 carbons (C8 and C10).
|trivial name
|systematic name
|number of carbons in chain
|typical sources
|lauric acid
|n-dodecanoic acid
|palm kernel oil, nutmeg
|myristic acid
|n-tetradecanoic acid
|palm kernel oil, nutmeg
|palmitic acid
|n-hexadecanoic acid
|olive oil, animal lipids
|stearic acid
|n-octadecanoic acid
|cocoa butter, animal lipids
|behenic acid
|n-docosanoic acid
|brain tissue, radish oil
|lignoceric acid
|n-tetracosanoic acid
|brain tissue, carnauba wax
Unsaturated fatty acids
Unsaturated fatty acids have one or more carbon-carbon double bonds. The term unsaturated indicates that fewer than the maximum possible number of hydrogen atoms are bonded to each carbon in the molecule. The number of double bonds is indicated by the generic name—monounsaturated for molecules with one double bond or polyunsaturated for molecules with two or more double bonds. Oleic acid is an example of a monounsaturated fatty acid. Common representative monounsaturated fatty acids together with their names and typical sources are listed in the table. The prefix cis-9 in the systematic name of palmitoleic acid denotes that the position of the double bond is between carbons 9 and 10. Two possible conformations, cis and trans, can be taken by the two CH2 groups immediately adjacent to the double-bonded carbons. In the cis configuration, the one occurring in all biological unsaturated fatty acids, the two adjacent carbons lie on the same side of the double-bonded carbons. In the trans configuration, the two adjacent carbons lie on opposite sides of the double-bonded carbons.
|trivial name
|systematic name
|number of carbons in chain
|typical sources
|palmitoleic acid
|cis-9-hexadecenoic acid
|marine algae, pine oil
|oleic acid
|cis-9-octadecenoic acid
|animal tissues, olive oil
|gadoleic acid
|cis-9-eicosenoic acid
|fish oils (cod, sardine)
|erucic acid
|cis-13-docosenoic acid
|rapeseed oil
|nervonic acid
|cis-15-tetracosenoic acid
|sharks, brain tissue
Fatty acids containing more than one carbon-carbon double bond (polyunsaturated fatty acids) are found in relatively minor amounts. The multiple double bonds are almost always separated by a CH2 group (―CH2―CH=CH―CH2―CH=CH―CH2―), a regular spacing motif that is the result of the biosynthetic mechanism by which the double bonds are introduced into the hydrocarbon chain. The table lists the most common polyunsaturated fatty acids, linoleic and arachidonic, together with several that are less common. Arachidonic acid (C20) is of particular interest as the precursor of a family of molecules, known as eicosanoids (from Greek eikosi, "twenty"), that includes prostaglandins, thromboxanes, and leukotrienes. These compounds, produced by cells under certain conditions, have potent physiological properties, as explained in the section Intracellular and extracellular messengers. Animals cannot synthesize two important fatty acids, linoleic acid (an omega-6 fatty acid) and alpha-linolenic acid (an omega-3 fatty acid), that are the precursors of the eicosanoids and so must obtain them in the diet from plant sources. For this reason, these precursors are called essential fatty acids.
|trivial name
|systematic name
|number of carbons in chain
|typical sources
|linoleic acid
|cis-9-, cis-12-octadecadienoic acid
|corn oil, animal tissues, bacteria
|linolenic acid
|cis-9-, cis-12-, cis-15-octadecatrienoic acid
|animal tissues
|5,8,11-eicosatrienoic acid
|8,11,14-eicosatrienoic acid
|brain tissue
|7,10,13-docosatrienoic acid
|8,11,14-docosatrienoic acid
|arachidonic acid
|5,8,11,14-eicosatetraenoic acid
|liver, brain tissue
|4,7,10,13-docosatetraenoic acid
|brain tissue
|4,7,10,13,16,19-docosahexaenoic acid
|brain tissue
Trans polyunsaturated fatty acids, although not produced biosynthetically by mammals, are produced by microorganisms in the gut of ruminant animals such as cows and goats, and they are also produced synthetically by partial hydrogenation of fats and oils in the manufacture of margarine (the so-called trans fats). There is evidence that ingestion of trans fats can have deleterious metabolic effects.
Learn More in these related Britannica articles:
metabolism: Lipid componentsThe component building blocks of the lipids found in storage fats, in lipoproteins (combinations of lipid and protein), and in the membranes of cells and organelles are glycerol, the fatty acids, and a number of other compounds (e.g., serine, inositol).…
human nutrition: Lipids) Lipids also contain carbon, hydrogen, and oxygen but in a different configuration, having considerably fewer oxygen atoms than are found in carbohydrates. Lipids are soluble in organic solvents (such as acetone or ether) and insoluble in water, a property that is readily seen when…
photosynthesis: LipidsLamellae consist of about equal amounts of lipids and proteins. About one-fourth of the lipid portion of the lamellae consists of pigments and coenzymes; the remainder consists of various lipids, including polar compounds such as phospholipids and galactolipids. These polar lipid molecules have "head"…
nutrition: Lipids (fats and oils)Another form in which some plants store energy in their seeds is fat, commonly called oil in its liquid form. In animals, fats form the only large-scale energy store. Fats are a more concentrated energy source than carbohydrates; oxidation yields roughly…
cell: Chemical composition and membrane structure…composed of proteins and fatty-acid-based lipids. Membranes actively involved in metabolism contain a higher proportion of protein; thus, the membrane of the mitochondrion, the most rapidly metabolizing organelle of the cell, contains as much as 75 percent protein, while the membrane of the Schwann cell, which forms an insulating sheath…
More About Lipid29 references found in Britannica articles
Assorted References
- biochemical study
- endoplasmic reticulum
- Golgi apparatus
- importance to metabolism
- increase during pregnancy
- kinase
- In kinase
- lipid storage disease
- nutritional requirement


text:
The Atlanta Gas Light Company has filed with the Georgia Public Service Commission a Request to Amend its 2010-2013 Capacity Supply Plan. Copies of this filing are on file with the Georgia Public Service Commission. This matter has been assigned Docket No. 31491 and has been scheduled for public hearing before the Georgia Public Service Commission beginning October 2, 2012 immediately following the 10:00 a.m. Administrative Session in Room 110 of the Georgia Public Service Commission offices located at 244 Washington Street, SW, Atlanta, Georgia 30334. Any one interested in this matter will be given the opportunity to express his or her view pursuant to O.C.G.A. Section 46-2-59.
In accordance with O.C.G.A. Section 46-2-59(c), persons wishing to intervene must file a Petition to Intervene with the Georgia Public Service Commission within thirty (30) days of the first publication of this notice.
An original and fifteen (15) copies of any pre-filed testimony of statements by interveners along with a 3 1/2 inch diskette or CD ROM containing an electronic version of this filing in Microsoft Word for text documents or Excel for spread sheets must be filed with the Georgia Public Service Commission?s Executive Secretary by 4:00 p.m. on September 10, 2012 in accordance with the Procedural and Scheduling Order issued in this docket. Any expert testimony or testimony of a technical nature must by pre-filed. Parties of record must also file with one another copies of any pre-filed testimony. Hearings on intervenor testimony will be heard beginning October 2, 2012.
If you have a disability and will need assistance or accommodations to participate, or need further information, please contact the Executive Secretary's Office, Georgia Public Service Commission at (404) 656-4501 or 1-800-282-5813 (inside Georgia only) at least one day prior to the hearing in this matter.
This notice is published at the direction of the Georgia Public Service Commission.
David C. Weaver
Vice President
Regulatory and Governmental Affairs
Atlanta Gas Light Company
gpn16 ATLANTA GAS LIGHT COMPANY LEGAL NOTICE
No Trackbacks
Display comments as (Linear | Threaded)


text:
Governments combine data centers to save money.
Data centers and consolidation. The two seem to be joined at the hip these days. As in the corporate world, data centers have become the hearts of government operations, pumping the lifeblood of information into the organization.
But data centers have proliferated at a bewildering and unsustainable pace, driving up the cost of IT in government. As the need for more interoperability, shared services and enterprise applications grows, CIOs see an opportunity to consolidate, reduce redundancy and pare down expenses.
As a result, data center consolidation has become a significant factor in public-sector IT. At the federal, state and local levels, CIOs are embarking on efforts to centralize server farms and their administration.
But is consolidation the panacea to what ails government IT? In the article Same Old Song, Contributing Writer and former Deputy CIO of Missouri William Bott says CIOs must ask themselves why they are consolidating before they take the plunge.
Still, data centers --consolidated or not -- are huge expenses and in the present economic situation, public CIOs are under more pressure than ever to reduce costs. Are there some relatively painless ways to cut data center costs? Eric Gallant of Lee Technologies thinks so and in this report, he highlights five quick and relatively easy ways to save money.
Five Budget-Saving Ways to Maintain Data Center Uptime, by Eric Gallant, Lee Technologies
Advice: Information Technology Use More Important Than Consolidation, by Bill Bott, Change & Innovation Agency


text:
Donte Stallworth spent a decade as an NFL wide receiver, playing for six different teams, but what he'll always be most known for is the morning of March 14, 2009, when Stallworth struck and killed a man named Mario Reyes, a crash that led to a conviction for DUI manslaughter.
The NFL, hoping other rookies can learn from Stallworth, has asked him to speak at this weekend's rookie symposium. Stallworth said in a FOX Sports interview with his former teammate Brendon Ayanbadejo that he'll tell this year's draft class that they need to make the decision not to drink and drive, and that making the wrong decision once can have dire consequences.
"These things are totally preventable. I've heard some people call them accidents. They are not an accident. It is not an accident when you decide to drive after you have been drinking," Stallworth said. "We're all grown enough to make decisions. So that means you are grown enough to formulate a plan before going out and you know you are going to have drinks, or you know there is an opportunity or chance for you to have drinks, then you should plan ahead. And that is one of the biggest messages I want to get across to these guys. DUIs are not accidents. They don't happen by accident. You don't drink alcohol and get in your car by accident. If you plan ahead, I think that it is one of the issues I am going to try and hit home with the rookies when I speak to them."
Nothing Stallworth goes through will ever equal what Reyes's family has to endure, but Stallworth does want rookies to know that one bad decision can affect them for life. In addition to spending a month in jail and a year under suspension from the NFL, Stallworth can never drive a car again.
"My driver's license is banned for life," he said. "I have been taking taxis, catching car services. This is part of my story, part of my life. I can't complain at all. It is something that is another part of my story that I want to relay to these guys and let them know how fast things can change in an instant from a terrible decision."
Stallworth wants players to think about him, and think about Mario Reyes, when they're out drinking.
"It is something I will live with for the rest of my life," he said. "It is something when I eventually have children one day that I will have to explain to them why their father made this decision and what they can learn from my mistake and my decision. I want it to resonate with these young guys. DUIs are totally preventable."
That's a message that should go without saying, but needs to be repeated often.


text:
You don't think of a lab coat as summer wear for teens, but we don't quite feel like it's summer around here until our research interns have arrived. Early in June, INBT's undergraduate nano-bio researchers arrived. This week our high schoolers in the Summer Academic Research Experience (SARE) scholars got started.
SARE pairs specially selected teens with university mentors who guide them through a mini research project. At the end of their time here, they hold a small poster session. The students gain valuable work skills, learn about scientific careers, get tutoring help, practice their writing, gather data for their projects and earn some cash for the future. Students in the program are recruited from the Boys Hope Girls Home of Baltimore program, The SEED School of Maryland and The Crossroads School, all of which assist in differing ways with in the education, housing, tutoring and counseling of promising young people from disadvantaged circumstances.
The SARE program was launched in 2009 by Doug Robinson, professor in the cell biology department at the School of Medicine, and is funded jointly by the medical school and Johns Hopkins Institute for NanoBioTechnology.
This year's SARE scholars include: Diana Bobb is being mentored by Makoto Tanigawa in the Takanari Inoue Lab in the Department of Cell Biology; Kaleel Byrd is being mentored by Ryan Vierling in the Caren Meyers Lab in the Department of Pharmacology; Milan Dower is being mentored by Tom Lampert in the Peter Devreotes Lab in the Department of Cell Biology; Jewel Herndon is being mentored by Herschel Wade in his lab in the Department of Biophysics; De'Sean Markley is being mentored by Hoku West-Foyle in the Douglas Robinson Lab in the Department of Cell Biology


text:
Horse Power - New Mustang and Ford Products - February 2014
The latest parts, components, and more for your Fast Ford
Kenny Brown Performance is proud to announce its new Street-Sport shock and spring package for '05-'14 Mustangs. Customers can choose between Touring or Sport spring rates, with the added feature of ride-height adjustability. Each package is manufactured from stainless steel and features high-quality hardware for a long life and reliability.
Web www.kennybrown.com Phone 855/847-4477
Seal This
If you're an '83-'93 Mustang convertible owner, than check this out. National Parts Depot now offers brand-new quarter-lock pillar seals. According to NPD, the factory pieces often times did not seal correctly, leaving your vehicle vulnerable to water leakage. Its units have now been redesigned to offer a tight-fit seal—better than the originals. Price comes in at $29.95 for the pair.
Web www.npdlink.com Phone 800/874-7595
AmericanMuscle.com has recently released its all-new MMD hood-vent louvers for '05-'09 Mustangs. Its louvers offer the same styling currently available on the '13 Mustang GT, and are a fully functional heat extractor. Each piece comes in a matte-black finish, and is made from ultra-durable, high-impact ABS plastic. Available for $174.99.
Web www.americanmuscle.com Phone 866/727-1266
Stay Cool
JLT Performance is proud to unveil its latest addition to its performance lineup, a '13-'14 Mustang brake cooling kit. Designed to help bring air to the center of the rotor for even cooling, this kit is a must-have if you're an avid street or road racer. Included in the kit is a backing plate, 2-1/2-inch brake cooling hose, and all the necessary hardware. Pricing starts at $199.
Web www.jlttruecoldair.com Phone 757/335-1940
Bump Up the Power
Add an SVE underdrive pulley and belt kit to your '87-'93 5.0L Fox-body Mustang for reduced accessory-drive drag and increased power thanks to LatemodelRestoration.com. Included with its underdrive pulley kit comes a Goodyear Gatorback belt, giving you everything needed for the swap, saving you time and money.
Web www.latemodelrestoration.com Phone 866/507-3786
Got Fuel?
Aeromotive has developed a universal high-performance fuel system that can be installed into almost any gas tank. Known as its Phantom fuel system, it comes as a complete kit and includedes a baffle/basket assembly that controls fuel slosh, and an in-tank Stealth fuel pump capable of supporting high horsepower on both electronic fuel-injected and carburated vehicles. Say goodbye to cavitation and vapor lock.
Web www.aeromotiveinc.com Phone 913/647-7300
The Dyad DS multi-disc clutches by Centerforce is now available for '09-'13 Ford Shelby GT500 Mustangs. With a torque capacity rating of 1,300 lb-ft, its new multi-disc clutch system replaces the current pressure plate, disc, and flywheel assembly with a higher-holding-capacity system designed for a direct bolt-in replacement.
Web www.centerforce.com Phone 928/771-8422
EcoBoost Upgrade
If you've been looking for a way to upgrade your '10-to-present EcoBoost Ford Taurus, then look to Stainless Works. SW has released its new 2.50-inch downpipe system. Made from 304-stainless steel, choose between an off-road or catted version. This system fits to the factory connection points or to the Stainless Works' Ford SHO exhaust. Made in the USA, each piece features a lifetime guarantee on materials and workmanship, and includes all necessary hardware for installation. Retail price is $640.
Web www.stainlessworks.net Phone 800/878-3635


text:
- Introduction
- Before you start
- Input/output: A conceptual overview
- Channels and buffers
- From theory to practice: Reading and writing in NIO
- Buffer internals
- More about buffers
- Scattering and gathering
- File locking
- Networking and asynchronous I/O
- Character sets
- Summary
- Downloadable resources
- Related topics
- Comments
Getting started with new I/O (NIO)
Before you start
About this tutorial
The new input/output (NIO) library was introduced with JDK 1.4. Picking up where original I/O leaves off, NIO provides high-speed, block-oriented I/O in standard Java code. By defining classes to hold data, and by processing that data in blocks, NIO takes advantage of low-level optimizations in a way that the original I/O package could not, without using native code.
In this tutorial, we'll cover almost every aspect of the NIO library, from the high-level conceptual stuff to under-the-hood programming detail. In addition to learning about crucial I/O elements like buffers and channels, you'll have the opportunity to see how standard I/O works in the updated library. You'll also learn about things you can only do with NIO, such as asynchronous I/O and direct buffers.
Throughout the tutorial, we'll work with code samples that illustrate different aspects of the NIO library. Almost every code sample is part of an extended Java program, which you'll find in Related topics. As you are working through the exercises, you're encouraged to download, compile, and run these programs on your own system. The code will also come in handy when you're done with the tutorial, providing a starting point for your NIO programming efforts.
This tutorial is intended for any programmer who wants to learn more about
the JDK 1.4 NIO library. To get the most from the discussion you should
understand basic Java programming concepts such as classes, inheritance,
and using packages. Some familiarity with the original I/O library (from
java.io.* package) will also be helpful.
While this tutorial does require a working vocabulary and conceptual understanding of the Java language, it does not require a lot of actual programming experience. In addition to explaining thoroughly all the concepts relevant to the tutorial, I've kept the code examples fairly small and simple. The goal is to provide an easy entry point for learning about NIO, even for those who don't have much Java programming experience.
How to run the code
The source code archive (available in Related topics ) contains all of the programs used in this tutorial. Each program consists of a single Java file. Each file is identified by name and easily related to the programming concept it illustrates.
Some of the programs in the tutorial require command-line arguments to run. To run a program from the command line, simply go to your nearest command-line prompt. Under Windows, the command-line prompt is the "Command" or "command.com" program. Under UNIX, any shell will do.
You will need to have JDK 1.4 installed and in your path to complete the exercises in the tutorial. See Related topics if you need help installing and configuring JDK 1.4.
Input/output: A conceptual overview
Intro to I/O
I/O -- or input/output -- refers to the interface between a computer and the rest of the world, or between a single program and the rest of the computer. It is such a crucial element of any computer system that the bulk of any I/O is actually built into the operating system. Individual programs generally have most of their work done for them.
In Java programming, I/O has until recently been carried out using a
stream metaphor. All I/O is viewed as the movement of single
bytes, one at a time, through an object called a
Stream I/O is used for contacting the outside world. It is also used
internally, for turning objects into bytes and then back into objects.
NIO has the same role and purpose as original I/O, but it uses a different metaphor -- block I/O. As you will learn in this tutorial, block I/O can be a lot more efficient than stream I/O.
Why NIO?
NIO was created to allow Java programmers to implement high-speed I/O without having to write custom native code. NIO moves the most time-consuming I/O activities (namely, filling and draining buffers) back into the operating system, thus allowing for a great increase in speed.
Streams versus blocks
The most important distinction between the original I/O library (found in
java.io.* ) and NIO has to do with how data is packaged and
transmitted. As previously mentioned, original I/O deals with data in
streams, whereas NIO deals with data in blocks.
A stream-oriented I/O system deals with data one byte at a time. An input stream produces one byte of data, and an output stream consumes one byte of data. It is very easy to create filters for streamed data. It is also relatively simply to chain several filters together so that each one does its part in what amounts to a single, sophisticated processing mechanism. On the flip side, stream-oriented I/O is often rather slow.
A block-oriented I/O system deals with data in blocks. Each operation produces or consumes a block of data in one step. Processing data by the block can be much faster than processing it by the (streamed) byte. But block-oriented I/O lacks some of the elegance and simplicity of stream-oriented I/O.
Integrated I/O
The original I/O package and NIO have been well integrated in JDK 1.4.
java.io.* has been reimplemented using NIO as its base, so
it can now take advantage of some features of NIO. For example, some of
the classes in the
java.io.* package contain methods to read
and write data in blocks, which leads to faster processing even in more
stream-oriented systems.
It is also possible to use the NIO library to implement standard I/O functions. For example, you could easily use block I/O to move data one byte at a time. But as you will see, NIO also offers many advantages that are not available from the original I/O package.
Channels and buffers
Channels and buffers overview
Channel s and
Buffer s are the central objects
in NIO, and are used for just about every I/O operation.
Channels are analogous to streams in the original I/O package. All data
that goes anywhere (or comes from anywhere) must pass through a
Channel object. A
Buffer is essentially a
container object. All data that is sent to a channel must first be placed
in a buffer; likewise, any data that is read from a channel is read into a
In this section, you will learn about working with channels and buffers in NIO.
What is a buffer?
Buffer is an object, which holds some data, that is to be
written to or that has just been read from. The addition of the
Buffer object in NIO marks one of the most significant
differences between the new library and original I/O. In stream-oriented
I/O, you wrote data directly to, and read data directly from,
Stream objects.
In the NIO library, all data is handled with buffers. When data is read, it is read directly into a buffer. When data is written, it is written into a buffer. Anytime you access data in NIO, you are pulling it out of the buffer.
A buffer is essentially an array. Generally, it is an array of bytes, but other kinds of arrays can be used. But a buffer is more than just an array. A buffer provides structured access to data and also keeps track of the system's read/write processes.
Kinds of buffers
The most commonly used kind of buffer is the
ByteBuffer. A
ByteBuffer allows get/set operations (that is, the getting
and setting of bytes) on its underlying byte array.
ByteBuffer is not the only type of buffer in NIO. In fact,
there is a buffer type for each of the primitive Java types:
Each of the
Buffer classes is an instance of the
Buffer interface. With the exception of
ByteBuffer, each one has the exact same operations,
differing only in the type of data it deals with. Because
ByteBuffer is used for most standard I/O operations it has
all of the shared buffer operations as well as some that are unique.
You may want to take a moment now to run the UseFloatBuffer.java, which contains an example of typed buffers in action.
What is a channel?
Channel is an object from which you can read data and to
which you can write data. Comparing NIO with original I/O, a channel is
like a stream.
As previously mentioned, all data is handled through
objects. You never write a byte directly to a channel; instead you write
to a buffer containing one or more bytes. Likewise, you don't read a byte
directly from a channel; you read from a channel into a buffer, and then
get the bytes from the buffer.
Kinds of channels
Channels differ from streams in that they are bi-directional. Whereas
streams only go in one direction (a stream must be a subclass of either
InputStream or
OutputStream ), a
Channel can be opened for reading, for writing, or for
Because they are bi-directional, channels better reflect the reality of the underlying operating system than streams do. In the UNIX model in particular, the underlying operating system channels are bi-directional.
From theory to practice: Reading and writing in NIO
NIO overview
Reading and writing are the fundamental processes of I/O. Reading from a channel is simple: we simply create a buffer and then ask a channel to read data into it. Writing is also fairly simply: we create a buffer, fill it with data, and then ask a channel to write from it.
In this section, we'll learn a little bit about reading and writing data in Java programs. We'll go over the main components of NIO (buffers, channels, and some related methods) and see how they interact for reading and writing. In the sections that follow, we will look at each of these components and interactions in more detail.
Reading from a file
For our first exercise, we'll read some data from a file. If we were using
original I/O, we would simply create a
FileInputStream and
read from that. In NIO, however, things work a little differently: we
first get a
Channel object from the
FileInputStream, and then use that channel to read the
Any time you perform a read operation in an NIO system, you are reading from a channel, but you don't read directly from a channel. Since all data ultimately resides in the buffer, you read from a channel into a buffer.
So reading from a file involves three steps: (1) getting the
Channel from
FileInputStream; (2) creating the
Buffer; and (3) reading from the
Channel into
Now, let's see how this works.
Three easy steps
Our first step is to get a channel. We get the channel from the
FileInputStream fin = new FileInputStream( "readandshow.txt" ); FileChannel fc = fin.getChannel();
The next step is to create a buffer:
ByteBuffer buffer = ByteBuffer.allocate( 1024 );
And, finally, we need to read from the channel into the buffer, as shown here:
fc.read( buffer );
You'll notice that we didn't need to tell the channel how much to read into the buffer. Each buffer has a sophisticated internal accounting system that keeps track of how much data has been read and how much room there is for more data. We'll talk more about the buffer accounting system in the Buffer internals overview.
Writing to a file
Writing to a file in NIO is similar to reading from one. We start by
getting a channel from a
FileOutputStream fout = new FileOutputStream( "writesomebytes.txt" ); FileChannel fc = fout.getChannel();
Our next step is to create a buffer and put some data in it -- in this
case, the data will be taken from an array called
which contains the ASCII bytes for the string "Some bytes." (The
buffer.flip() and
buffer.put() calls will be
explained later in the tutorial.)
ByteBuffer buffer = ByteBuffer.allocate( 1024 ); for (int i=0; i<message.length; ++i) { buffer.put( message[i] ); } buffer.flip();
Our final step is to write to the buffer:
fc.write( buffer );
Notice that once again we did not need to tell the channel how much data we wanted to write. The buffer's internal accounting system keeps track of how much data it contains and how much is left to be written.
Reading and writing together
Next we'll see what happens when we combine reading and writing. We'll
base this exercise on a simple program called CopyFile.java, which copies
all the data from one file to another one. CopyFile.java carries out three
basic operations: it first creates a
Buffer, then reads data
from the source file into this buffer, and then writes the buffer to the
destination file. The program repeats -- read, write, read, write -- until
the source file is exhausted.
The CopyFile program will let you see how we check the status of an
operation, as well as how we use the
clear() and
flip() methods to reset the buffer and prepare it to have
newly read data written to another channel.
Running the CopyFile example
Because the buffer tracks its own data, the inner loop of the CopyFile program is very simple, as shown below:
fcin.read( buffer ); fcout.write( buffer );
The first line reads data into the buffer from the input channel,
fcin, and the second line writes the data to the output
Checking the status
Our next step is to check to see when we're done copying. We're done when
there's no more data, and we can tell this when the
method returns
-1, as shown below:
int r = fcin.read( buffer ); if (r==-1) { break; }
Resetting the buffer
And, finally, we call the
clear() method before we read into
a buffer from the input channel. Likewise, we call the
flip() method before we write a buffer to the output
channel, as shown below:
buffer.clear(); int r = fcin.read( buffer ); if (r==-1) { break; } buffer.flip(); fcout.write( buffer );
clear() method resets the buffer, making it ready to
have data read into it. The
flip() method prepares the
buffer to have the newly-read data written to another channel.
Buffer internals
Buffer internals overview
In this section, we'll look at two important components of buffers in NIO: state variables and accessor methods.
State variables are key to the "internal accounting system" mentioned in the previous section. With each read/write operation, the buffer's state changes. By recording and tracking those changes, a buffer is able to internally manage its own resources.
When you read data from a channel, the data is placed in a buffer. In some
cases, you can write this buffer directly to another channel, but often,
you'll want to look at the data itself. This is accomplished using the
accessor method
get(). Likewise, when you want
to put raw data in a buffer, you use the accessor method
In this section, you'll learn about state variables and accessor methods in NIO. Each component will be described, and then you'll have the opportunity to see it in action. While NIO's internal accounting system might seem complicated at first, you'll quickly see that most of the real work is done for you. The bookkeeping you're probably accustomed to coding by hand -- using byte arrays and index variables -- is handled internally in NIO.
State variables
Three values can be used to specify the state of a buffer at any given moment in time:
Together, these three variables track the state of the buffer and the data it contains. We'll examine each one in detail, and also see how they fit into a typical read/write (input/output) process. For the sake of the example, we'll assume that we are copying data from an input channel to an output channel.
You will recall that a buffer is really just a glorified array. When you
read from a channel, you put the data that you read into an underlying
array. The
position variable keeps track of how much data
you have written. More precisely, it specifies into which array element
the next byte will go. Thus, if you've read three bytes from a channel
into a buffer, that buffer's
position will be set to 3,
referring to the fourth element of the array.
Likewise, when you are writing to a channel, you get the data from a
buffer. The
position value keeps track of how much you have
gotten from the buffer. More precisely, it specifies from which array
element the next byte will come. Thus, if you've written 5 bytes to a
channel from a buffer, that buffer's
position will be set to
5, referring to the sixth element of the array.
limit variable specifies how much data there is left to
get (in the case of writing from a buffer into a channel), or how much
room there is left to put data into (in the case of reading from a channel
into a buffer).
position is always less than, or equal to, the
capacity of a buffer specifies the maximum amount of
data that can be stored therein. In effect, it specifies the size of the
underlying array -- or, at least, the amount of the underlying array that
we are permitted to use.
limit can never be larger than the
Observing the variables
We'll start with a newly created buffer. For the sake of the example,
let's assume that our buffer has a total
capacity of eight
bytes. The
Buffer 's state is shown here:
React operations
Recall that the
limit can never be larger than the
capacity, and in this case both values are set to 8. We show
this by pointing them off the end of the array (which is where slot 8
would be if there were a slot 8):
React operations
position is set to 0. If we read some data into the
buffer, the next byte read will go into slot 0. If we write from the
buffer, the next byte taken from the buffer will be taken from slot 0. The
position setting is shown here:
React operations
Because the
capacity is not going to change, we can omit it
from the discussion that follows.
The first read
Now we are ready to begin read/write operations on our newly created
buffer. We start by reading some data from our input channel into the
buffer. The first read gets three bytes. These are put into the array
starting at the
position, which was set to 0. After this
read, the position is increased to 3, as shown here:
React operations
limit is unchanged.
The second read
For our second read, we read two more bytes from the input channel into
our buffer. The two bytes are stored at the location pointed to by
position is thus increased by
React operations
limit is unchanged.
The flip
Now we are ready to write our data to an output channel. Before we can do
this, we must call the
flip() method. This method does two
crucial things:
- It sets the
limitto the current
- It sets the
positionto 0.
The figure on the section shows our buffer before the flip. Here is the buffer after the flip:
React operations
We are now ready to begin writing data to a channel from the buffer. The
position has been set to 0, which means the next byte we get
will be the first one. And the
limit has been set to the old
position, which means that it just includes all the bytes we
read before, and no more.
The first write
In our first write, we take four bytes from the buffer and write them to
our output channel. This advances the
position to 4, and
leaves the
limit unchanged, as shown here:
React operations
The second write
We only have one byte left to write. The
limit was set to 5
when we did our
flip(), and the
cannot go past the
limit. So the last write takes one byte
from our buffer and writes it to the output channel. This advances the
position to 5, and leaves the
limit unchanged,
as shown here:
React operations
The clear
Our final step is to call the buffer's
clear() method. This
method resets the buffer in preparation for receiving more bytes.
Clear does two crucial things:
- It sets the
limitto match the
- It sets the
positionto 0.
This figure shows the state of the buffer after
clear() has
been called:
React operations
The buffer is now ready to receive fresh data.
Accessor methods
So far, we've only used buffers to move data from one channel to another. Frequently, however, your program will need to deal directly with the data. For example, you might want to save user data to disk. In this case, you'll have to put that data directly into a buffer, and then write the buffer to disk using a channel.
Or, you might want to read user data back in from disk. In this case, you would read the data into a buffer from a channel, and then examine the data in the buffer.
We'll close this section with a detailed look at accessing data directly
in the buffer, using the
get() and
methods for the
ByteBuffer class.
The get() methods
In the
ByteBuffer class, there are four
byte get();
ByteBuffer get( byte dst[] );
ByteBuffer get( byte dst[], int offset, int length );
byte get( int index );
The first method gets a single byte. The second and third methods read a
group of bytes into an array. The fourth method gets the byte from a
particular position in the buffer. The methods that return a
ByteBuffer simply return the
this value on
which they are called.
Additionally, we say that the first three
get() methods are
relative, while the last one is absolute. Relative means that
limit and
position values are respected by
get() operation -- specifically, the byte is read from
the current
position, and the
position is
incremented after the
get. An absolute method, on
the other hand, ignores the
limit and
values, and does not affect them. In effect, it bypasses the buffer's
accounting methods entirely.
The methods shown above correspond to the
ByteBuffer class.
The other classes have equivalent
get() methods that are
identical except that rather than dealing with bytes, they deal with the
type appropriate for that buffer class.
The put() methods
In the
ByteBuffer class, there are five
ByteBuffer put( byte b );
ByteBuffer put( byte src[] );
ByteBuffer put( byte src[], int offset, int length );
ByteBuffer put( ByteBuffer src );
ByteBuffer put( int index, byte b );
The first method
put s a single byte. The second and third
methods write a group of bytes from an array. The fourth method copies
data from the given source
ByteBuffer into this
ByteBuffer. The fifth method puts the byte into the buffer
at a particular
position. The methods that return a
ByteBuffer simply return the
this value on
which they are called.
As with the
get() methods, we characterize the
put() methods as being relative or
absolute. The first four methods are relative, while the fifth
one is absolute.
The methods shown above correspond to the
ByteBuffer class.
The other classes have equivalent
put() methods that are
identical except that rather than dealing with bytes, they deal with the
type appropriate for that buffer class.
Typed get() and put() methods
In addition to the
get() and
put() methods
described previously,
ByteBuffer also has extra methods for
reading and writing values of different types, as follows:
Each of these methods, in fact, comes in two varieties -- one relative and one absolute. They are useful for reading formatted binary data, such as the header of an image file.
You can see these methods in action in the example program TypesInByteBuffer.java.
The buffer at work: An inner loop
The following inner loop summarizes the process of using a buffer to copy data from an input channel to an output channel.
while (true) { buffer.clear(); int r = fcin.read( buffer ); if (r==-1) { break; } buffer.flip(); fcout.write( buffer ); }
read() and
write() calls are greatly
simplified because the buffer takes care of many of the details. The
clear() and
flip() methods are used to switch
the buffer between reading and writing.
More about buffers
Buffers overview
Thus far, you have learned most of what you need to know about buffers to use them on a day-to-day basis. Our examples haven't strayed much beyond the kind of standard read/write procedures you could just as easily implement in original I/O as in NIO.
In this section, we'll get into some of the more complex aspects of working with buffers, such as buffer allocation, wrapping, and slicing. We'll also talk about some of the new features NIO brings to the Java platform. You'll learn how to create different types of buffers to meet different goals, such as read-only buffers, which protect data from modification, and direct buffers, which map directly onto the underlying OS buffers. We'll close the section with an introduction to creating memory-mapped files in NIO.
Buffer allocation and wrapping
Before you can read or write, you must have a buffer. To create a buffer,
you must allocate it. We allocate a buffer using the static
method of
ByteBuffer buffer = ByteBuffer.allocate( 1024 );
allocate() method allocates an underlying array of the
specified size and wraps it in a buffer object -- in this case a
You can also turn an existing array into a buffer, as shown here:
byte array[] = new byte[1024]; ByteBuffer buffer = ByteBuffer.wrap( array );
In this case, you've used the
wrap() method to wrap a buffer
around an array. You must be very careful about performing this type of
operation. Once you've done it, the underlying data can be accessed
through the buffer as well as directly.
Buffer slicing
slice() method creates a kind of sub-buffer
from an existing buffer. That is, it creates a new buffer that shares its
data with a portion of the original buffer.
This is best explained with an example. Let's start by creating a
ByteBuffer of length 10:
ByteBuffer buffer = ByteBuffer.allocate( 10 );
We fill this buffer with data, putting the number n in slot n:
for (int i=0; i<buffer.capacity(); ++i) { buffer.put( (byte)i ); }
Now we'll slice the buffer to create a sub-buffer that covers slots 3 through 6. In a sense, the sub-buffer is like a window onto the original buffer.
You specify the start and end of the window by setting the
position and
limit values, and then call the
slice() method:
buffer.position( 3 ); buffer.limit( 7 ); ByteBuffer slice = buffer.slice();
slice is a sub-buffer of
buffer. However,
slice and
buffer share the same underlying
data array, as we'll see in the next section.
Buffer slicing and data sharing
We've created a sub-buffer of our original buffer, and we know that the two buffers and the sub-buffers share the same underlying data array. Let's see what this means.
We run through the sub-buffer, and alter each element by multiplying it by 11. This changes, for example, a 5 into a 55.
for (int i=0; i<slice.capacity(); ++i) { byte b = slice.get( i ); b *= 11; slice.put( i, b ); }
Finally, let's take a look at the contents of the original buffer:
buffer.position( 0 ); buffer.limit( buffer.capacity() ); while (buffer.remaining()> 0) { System.out.println( buffer.get() ); }
The result shows that only the elements in the window of the sub-buffer were changed:
$ java SliceBuffer 0 1 2 33 44 55 66 7 8 9
Slice buffers are excellent for facilitating abstraction. You can write your functions to process an entire buffer, and if you find you want to apply that process to a sub-buffer, you can just take a slice of the main buffer and pass that to your function. This is easier than writing your functions to take additional parameters specifying what portion of the buffer should be acted upon.
Read-only buffers
Read-only buffers are very simple -- you can read them, but you can't
write to them. You can turn any regular buffer into a read-only buffer by
calling its
asReadOnlyBuffer() method, which returns a new
buffer that is identical to the first (and shares data with it), but is
Read-only buffers are useful for protecting data. When you pass a buffer to a method of some object, you really have no way of knowing if that method is going to try to modify the data in the buffer. Creating a read-only buffer guarantees that the buffer won't be modified.
You cannot convert a read-only buffer to a writable buffer.
Direct and indirect buffers
Another useful kind of
ByteBuffer is the direct buffer. A
direct buffer is one whose memory is allocated in a special
way to increase I/O speed.
Actually, the exact definition of a direct buffer is implementation-dependent. Sun's documentation has this to say about direct buffers:
Given a direct byte buffer, the Java virtual machine will make a best effort to perform native I/O operations directly upon it. That is, it will attempt to avoid copying the buffer's content to (or from) an intermediate buffer before (or after) each invocation of one of the underlying operating system's native I/O operations.
You can see direct buffers in action in the example program FastCopyFile.java, which is a version of CopyFile.java that uses direct buffers for increased speed.
You can also create a direct buffer using memory-mapped files.
Memory-mapped file I/O
Memory-mapped file I/O is a method for reading and writing file data that can be a great deal faster than regular stream- or channel-based I/O.
Memory-mapped file I/O is accomplished by causing the data in a file to magically appear as the contents of a memory array. At first, this sounds like it simply means reading the entire file into memory, but in fact it does not. In general, only the parts of the file that you actually read or write are brought, or mapped, into memory.
Memory-mapping isn't really magical, or all that uncommon. Modern operating systems generally implement filesystems by mapping portions of a file into portions of memory, doing so on demand. The Java memory-mapping system simply provides access to this facility if it is available in the underlying operating system.
Although they are fairly simple to create, writing to memory-mapped files can be dangerous. By the simple act of changing a single element of an array, you are directly modifying the file on disk. There is no separation between modifying the data and saving it to a disk.
Mapping a file into memory
The easiest way to learn about memory mapping is by example. In the
example below, we want to map a
FileChannel (all or a
portion of it) into memory. For this we use the
FileChannel.map() method. The following line of code maps
the first 1024 bytes of a file into memory:
MappedByteBuffer mbb = fc.map( FileChannel.MapMode.READ_WRITE, 0, 1024 );
map() method returns a
which is a subclass of
ByteBuffer. Thus, you can use the
newly-mapped buffer as you would any other
ByteBuffer, and
the operating system will take care of doing the mapping for you, on
Scattering and gathering
Scattering and gathering overview
Scatter/gather I/O is a method of reading and writing that uses multiple buffers, rather than a single buffer, to hold data.
A scattering read is like a regular channel read, except that it reads data into an array of buffers rather than a single buffer. Likewise, a gathering write writes data from an array of buffers rather than a single buffer.
Scatter/gather I/O is useful for dividing a data stream into separate sections, which can help implement complicated data formats.
Scatter/gather I/O
Channels can optionally implement two new interfaces:
ScatteringByteChannel and
GatheringByteChannel. A
is a channel that has two additional read methods:
long read( ByteBuffer[] dsts );
long read( ByteBuffer[] dsts, int offset, int length );
long read() methods are rather like the standard
read methods, except that instead of taking a single buffer
they take an array of buffers.
In a scattering read, the channel fills up each buffer in turn. When it fills up one buffer, it starts filling the next one. In a sense, the array of buffers is treated like one big buffer.
Applications of scatter/gather
Scatter/gather I/O is useful for dividing a piece of data into sections. For example, you might be writing a networking application that uses message objects, and each message is divided into a fixed-length header and a fixed-length body. You create one buffer that's just big enough for the header, and another buffer that's just big enough for the body. When you put these two in an array and read into them using a scattering read the header and body will be neatly divided between two buffers.
The convenience that we already get from buffers applies to buffer arrays as well. Because each buffer keeps track of how much room it has for more data, the scattering read will automatically find the first buffer with room in it. After that's filled up, it moves onto the next one.
Gathering writes
A gathering write is like a scattering read, only for writing. It too has methods that take an array of buffers:
long write( ByteBuffer[] srcs );
long write( ByteBuffer[] srcs, int offset, int length );
A gathering write is useful for forming a single data stream from a group of separate buffers. In keeping with the message example described above, you could use a gathering write to automatically assemble the components of a network message into a single data stream for transmission across a network.
You can see scattering reads and gathering writes in action in the example program UseScatterGather.java.
File locking
File locking overview
File-locking can be confusing at first. It sounds like it refers to preventing programs or users from accessing a particular file. In fact, file locks are just like regular Java object locks -- they are advisory locks. They don't prevent any kind of data access; instead, they allow different parts of a system to coordinate through the sharing and acquisition of locks.
You can lock an entire file or a portion of a file. If you acquire an exclusive lock, then no one else can acquire a lock on that same file or portion of a file. If you acquire a shared lock, then others can acquire shared locks, but not exclusive locks, on that same file or portion of a file. File locking is not always done for the purpose of protecting data. For example, you might temporarily lock a file to ensure that a particular write operation is made atomically, without interference from other programs.
Most operating systems provide filesystem locks, but they don't all do it in the same way. Some implementations provide shared locks, while others provide only exclusive locks. And some implementations do, in fact, make a locked portion of a file inaccessible, although most do not.
In this section, you'll learn how to do a simple file locking procedure in NIO, and we'll also talk about some of the ways you can ensure your locked files are as portable as they can be.
Locking a file
To acquire a lock on a portion of a file, you call the
lock() method on an open
FileChannel. Note
that you must open the file for writing if you want to acquire an
exclusive lock.
RandomAccessFile raf = new RandomAccessFile( "usefilelocks.txt", "rw" ); FileChannel fc = raf.getChannel(); FileLock lock = fc.lock( start, end, false );
After you have the lock, you can carry out any sensitive operations that you need to, and then release the lock:
After you have released the lock, any other programs trying to acquire the lock will have a chance to do so.
The example program, UseFileLocks.java, is meant to be run in parallel with itself. This program acquires a lock on a file, holds it for three seconds, and then releases it. If you run several instances of this program at the same time, you can see each one acquiring the lock in turn.
File locking and portability
File locking can be tricky business, especially given the fact that different operating systems implement locks differently. The following guidelines will help you keep your code as portable as possible:
- Only use exclusive locks.
- Treat all locks as advisory.
Networking and asynchronous I/O
Networking and asynchronous I/O overview
Networking is an excellent foundation for learning about asynchronous I/O,
which is of course essential knowledge for anyone doing input/output
procedures in the Java language. Networking in NIO isn't much different
from any other operation in NIO -- it relies on channels and buffers, and
you acquire the channels from the usual
InputStream s and
OutputStream s.
In this section we'll start with the fundamentals of asynchronous I/O -- what it is and what it is not -- and then move on to a more hands-on, procedural example.
Asynchronous I/O
Asynchronous I/O is a method for reading and writing data without
blocking. Normally, when your code makes a
call, the code blocks until there is data to be read. Likewise, a
write() call will block until the data can be written.
Asynchronous I/O calls, on the other hand, do not block. Instead, you register your interest in a particular I/O event -- the arrival of readable data, a new socket connection, and so on -- and the system tells you when such an event occurs.
One of the advantages of asynchronous I/O is that it lets you do I/O from a great many inputs and outputs at the same time. Synchronous programs often have to resort to polling, or to the creation of many, many threads, to deal with lots of connections. With asynchronous I/O, you can listen for I/O events on an arbitrary number of channels, without polling and without extra threads.
We'll see asynchronous I/O in action by examining an example program called MultiPortEcho.java. This program is like the traditional echo server, which takes network connections and echoes back to them any data they might send. However, it has the added feature that it can listen on multiple ports at the same time, and deal with connections from all of those ports. And it does it all in a single thread.
The explanation in this section corresponds to the implementation of the
go() method in the source code for
MultiPortEcho, so take a look at the source for a fuller
picture of what is going on.
The central object in asynchronous I/O is called the
Selector. A
Selector is where you register
your interest in various I/O events, and it is the object that tells you
when those events occur.
So, the first thing we need to do is create a
Selector selector = Selector.open();
Later on, we will call the
register() method on various
channel objects, in order to register our interest in I/O events happening
inside those objects. The first argument to
register() is
always the
Opening a ServerSocketChannel
In order to receive connections, we need a
ServerSocketChannel. In fact, we need one for each of the
ports on which we are going to listen. For each of the ports, we open a
ServerSocketChannel, as shown here:
ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking( false ); ServerSocket ss = ssc.socket(); InetSocketAddress address = new InetSocketAddress( ports[i] ); ss.bind( address );
The first line creates a new
ServerSocketChannel and the
last three lines bind it to the given port. The second line sets the
ServerSocketChannel to be non-blocking. We must
call this method on every socket channel that we're using; otherwise
asynchronous I/O won't work.
Selection keys
Our next step is to register the newly opened
ServerSocketChannels with our
Selector. We do
this using the ServerSocketChannel.register() method, as shown below:
SelectionKey key = ssc.register( selector, SelectionKey.OP_ACCEPT );
The first argument to
register() is always the
Selector. The second argument,
OP_ACCEPT, here
specifies that we want to listen for accept events -- that is,
the events that occur when a new connection is made. This is the only kind
of event that is appropriate for a
Note the return value of the call to
register(). A
SelectionKey represents this registration of this channel
with this
Selector. When a
Selector notifies
you of an incoming event, it does this by supplying the
SelectionKey that corresponds to that event. The
SelectionKey can also be used to de-register the channel.
The inner loop
Now that we have registered our interest in some I/O events, we enter the
main loop. Just about every program that uses
Selectors uses
an inner loop much like this one:
int num = selector.select(); Set selectedKeys = selector.selectedKeys(); Iterator it = selectedKeys.iterator(); while (it.hasNext()) { SelectionKey key = (SelectionKey)it.next(); // ... deal with I/O event ... }
First, we call the
select() method of our
Selector. This method blocks until at least one of the
registered events occurs. When one or more events occur, the
select() method returns the number of events that occurred.
Next, we call the
Selector 's
method, which returns a
Set of the
SelectionKey objects for which events have occurred.
We process the events by iterating through the
and dealing with each one in turn. For each
you must determine what I/O event has happened and which I/O objects have
been impacted by that event.
Listening for new connections
At this point in the execution of our program, we've only registered
ServerSocketChannel s, and we have only registered them for
"accept" events. To confirm this, we call the
method on our
SelectionKey and check to see what kind of
event has occurred:
if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) { // Accept the new connection // ... }
Sure enough, the
readOps() method tells us that the event is
a new connection.
Accepting a new connection
Because we know there is an incoming connection waiting on this server
socket, we can safely accept it; that is, without fear that the
accept() operation will block:
ServerSocketChannel ssc = (ServerSocketChannel)key.channel(); SocketChannel sc = ssc.accept();
Our next step is to configure the newly-connected
SocketChannel to be non-blocking. And because the purpose of
accepting this connection is to read data from the socket, we must also
register the
SocketChannel with our
as shown below:
sc.configureBlocking( false ); SelectionKey newKey = sc.register( selector, SelectionKey.OP_READ );
Note that we've registered the
SocketChannel for
reading rather than accepting new connections, using
OP_READ argument to
Removing the processed SelectionKey
Having processed the
SelectionKey, we're almost ready to
return to the main loop. But first we must remove the processed
SelectionKey from the set of selected keys. If we do not
remove the processed key, it will still be present as an activated key in
the main set, which would lead us to attempt to process it again. We call
the iterator's
remove() method to remove the processed
Now we're set to return to the main loop and receive incoming data (or an incoming I/O event) on one of our sockets.
Incoming I/O
When data arrives from one of the sockets, it triggers an I/O event. This
causes the call to
Selector.select(), in our main loop, to
return with an I/O event or events. This time, the
SelectionKey will be marked as an
event, as shown below:
} else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) { // Read the data SocketChannel sc = (SocketChannel)key.channel(); // ... }
As before, we get the channel in which the I/O event occurred and process it. In this case, because this is an echo server, we just want to read the data from the socket and send it right back. See the source code (MultiPortEcho.java) in Related topics for details on this process.
Back to the main loop
Each time we return to the main loop we call the
method on our
Selector, and we get a set of
SelectionKey s. Each key represents an I/O event. We process
the events, remove the
SelectionKey s from the selected set,
and go back to the top of the main loop.
This program is a bit simplistic, since it aims only to demonstrate the
techniques involved in asynchronous I/O. In a real application, you would
need to deal with closed channels by removing them from the
Selector. And you would probably want to use more than one
thread. This program can get away with a single thread because it's only a
demo, but in a real-world scenario it might make more sense to create a
pool of threads for taking care of the time-consuming portions of I/O
event processing.
Character sets
Character sets overview
According to Sun's documentation, a
Charset is "a named
mapping between sequences of sixteen-bit Unicode characters and sequences
of bytes." In practice, a
Charset lets you read and write
character sequences in the most portable way possible.
The Java language is defined as being based on Unicode. In practice, however, many people write programs under the assumption that a single character is represented on disk, or in a network stream, as a single byte. This assumption works in many cases, but not all, and as computers become more Unicode-friendly, it becomes less true every day.
In this section, we'll see how to use
Charsets to process
textual data in conformance with modern text formats. The sample program
we'll work with here is rather simple; nevertheless, it touches on all the
crucial aspects of using
Charset s: creating a
Charset for a given character encoding, and using that
Charset to decode and encode text data.
To read and write text, we are going to use
CharsetDecoder s
CharsetEncoder s, respectively. There's a good reason
why these are called encoders and decoders. A
character no longer represents a particular bit-pattern, but
rather an entity within a character system. Thus, characters represented
by an actual bit pattern must therefore be represented in some particular
CharsetDecoder is used to convert the bit-by-bit
representation of a string of characters into actual
values. Likewise, a
CharsetEncoder is used to convert the
characters back to bits.
Next, we'll take a look at a program that reads and writes data using these objects.
The right way to process text
We'll take a look now at the example program, UseCharsets.java. This
program is very simple -- it reads some text from one file, and writes it
to another file. But it treats the data as textual data, and reads it into
CharBuffer using a
CharsetDecoder. Likewise,
it writes the data back out using a
We're going to assume that our characters are stored on disk in the ISO-8859-1 (Latin1) character set -- the standard extension of ASCII. Even though we must be prepared for Unicode, we also must realize that different files are stored in different formats, and ASCII is of course a very common one. In fact, every Java implementation is required to come complete with support for the following character encodings:
The sample program
After opening the appropriate files reading the input data into a
ByteBuffer called
inputData, our program must
create an instance of an ISO-8859-1 (Latin1) character set:
Charset latin1 = Charset.forName( "ISO-8859-1" );
Then, we create a decoder (for reading) and encoder (for writing):
CharsetDecoder decoder = latin1.newDecoder(); CharsetEncoder encoder = latin1.newEncoder();
To decode our byte data into a set of characters, we pass our
ByteBuffer to the
CharsetDecoder, resulting in
CharBuffer cb = decoder.decode( inputData );
If we wanted to process our characters, we could do it at this point in the program. But we only want to write it back out unchanged, so there's nothing to do.
To write the data back out, we must convert it back to bytes, using the
ByteBuffer outputData = encoder.encode( cb );
After the conversion is complete we can write the data out to a file.
As you've seen, there are a lot of features in the NIO library. While some of the new features -- file locking and character sets, for example -- provide new capabilities, many of the features excel in the area of optimization.
At a fundamental level, there's nothing that channels and buffers can do that we couldn't do using the old stream-oriented classes. But channels and buffers allow for the possibility of doing the same old operations much faster -- approaching the maximum allowed by the system, in fact.
But one of the greatest strengths of NIO is that it provides a new -- and much needed -- structuring metaphor for doing input/output in the Java language. Along with such new conceptual (and realizable) entities as buffers, channels, and asynchronous I/O comes the opportunity to rethink I/O procedures in your Java programs. In this way, NIO breathes new life into even the most familiar procedures of I/O and gives us the opportunity to do them differently, and better, than we have before.
Downloadable resources
Related topics
- Download nio-src.zip, the complete source for the examples in this tutorial.
- See the SDK Documentation for more information about installing and configuring JDK 1.4.
- The online API specification describes the classes and methods of NIO, in the autodoc format that you know and love.
- JSR 51 is the Java Community Process document that first specified the new features of NIO. In fact, NIO, as implemented in JDK 1.4, is a subset of the features described in this document.
- John Zukowski has written some good
articles about NIO for his Magic with Merlin column:
- " The ins and outs of Merlin's new I/O buffers " ( developerWorks, March 2003) is another look at buffer basics.
- Get a little deeper into NIO with Aruna Kalagnanam and Balu G's " Merlin brings nonblocking I/O to the Java platform " ( developerWorks, March 2002).
- Greg Travis examines NIO in his book, JDK 1.4 Tutorial (Manning Publications, March 2002).